월드와이드웹의 기능을 지배하는 기본 원칙 중 하나는 요청과 응답의 교환입니다. 웹 페이지에 액세스하기 위해 요청을 보내면 서버는 적절한 데이터로 응답합니다.
다양한 유형의 인터넷 통신을 관장하는 널리 사용되는 프로토콜에는 HTTP(하이퍼텍스트 전송 프로토콜), FTP(파일 전송 프로토콜), SMTP(단순 메일 전송 프로토콜)가 있습니다.
HTTP는 웹사이트를 보거나 웹 지원 앱을 사용할 때 일반적으로 사용하는 프로토콜입니다. 또한 Go를 비롯한 여러 프로그래밍 언어의 HTTP 요청으로 작업할 수도 있습니다.
HTTP 요청이란 무엇인가요?
HTTP는 웹 브라우저와 같은 클라이언트가 서버에 요청을 보내고 서버가 응답을 반환하는 방법을 정의합니다. HTTP 요청에는 클라이언트가 액세스하려는 리소스에 대한 정보가 포함됩니다. 요청 메시지는 일반적으로 리소스를 식별하는 URL과 헤더 및 쿼리 매개변수와 같은 기타 선택적 데이터로 구성됩니다.
HTTP 요청에는 GET, POST, PUT, DELETE, HEAD, OPTIONS, CONNECT 등 여러 가지 유형이 있습니다. 처음 네 가지 메서드 유형이 가장 일반적이며 각각 읽기, 만들기, 업데이트, 삭제 CRUD 작업을 미러링합니다.
PUT 요청 유형은 종종 PATCH 요청 유형과 같은 의미로 사용됩니다. 두 요청 유형은 동일한 목적을 달성하지만 요청에 포함할 데이터만 다릅니다.
일반적인 HTTP 메서드를 사용하여 요청 보내기
Go의 기본 제공 http 패키지는 웹 서버를 생성하고 HTTP 요청을 관리하는 데 사용할 수 있는 일련의 함수와 구조를 제공합니다. 매우 강력한 패키지이며 모든 Go 웹 프레임워크는 어떤 식으로든 이 패키지를 기반으로 구축됩니다. Go의 넷 패키지의 하위 패키지입니다.
Go에서 HTTP 요청을 생성하려면 http.NewRequest() 함수를 사용하여 적절한 메서드, URL, 헤더 및 요청 본문을 설정할 수 있습니다. 요청을 생성한 후 Go net/http 패키지의 http.Client{} 구조를 사용하여 요청을 실행하고 응답을 받을 수 있습니다.
다음 코드 샘플은 HTTP 요청을 테스트하기 위해 공개적으로 사용 가능한 API인 reqres.in 을 사용합니다. 이를 사용하여 Go 프로그램에서 GET, POST, PUT, DELETE 요청을 테스트할 수 있습니다.
POST 요청
아래 코드는 이름과 직업을 가진 새 사용자를 생성하기 위해 reqres.in의 /api/users 엔드포인트에 POST 요청을 전송하는 함수입니다.
package main
import (
"bytes"
"encoding/json"
"fmt"
"io"
"net/http"
)
func createUser(name, job string) {
fmt.Println("Creating user...")
apiUrl := "https://reqres.in/api/users"
userData := []byte(`{"name":"` + name + `","job":"` + job + `"}`)
// create new http request
request, error := http.NewRequest("POST", apiUrl, bytes.NewBuffer(userData))
request.Header.Set("Content-Type", "application/json; charset=utf-8")
// send the request
client := &http.Client{}
response, error := client.Do(request)
if error != nil {
fmt.Println(error)
}
responseBody, error := io.ReadAll(response.Body)
if error != nil {
fmt.Println(error)
}
formattedData := formatJSON(responseBody)
fmt.Println("Status: ", response.Status)
fmt.Println("Response body: ", formattedData)
// clean up memory after execution
defer response.Body.Close()
}
formatJSON은 출력 데이터의 형식을 지정하기 위해 작성할 수 있는 사용자 정의 함수입니다. 구현 방법은 다음과 같습니다.
// function to format JSON data
func formatJSON(data []byte) string {
var out bytes.Buffer
err := json.Indent(&out, data, "", " ")
if err != nil {
fmt.Println(err)
}
d := out.Bytes()
return string(d)
}
다음과 같은 프로그램에서 createUser() 함수를 호출할 수 있습니다:
func main() {
fmt.Println("Making POST request...")
createUser("Tim Omolana", "Writer")
}
터미널에서 go 실행 <파일명> 명령을 사용하여 프로그램을 실행하면 다음과 같은 출력을 볼 수 있습니다:
GET 요청
다음 코드는 reqres.in 서버에서 고유 ID를 사용하여 사용자를 검색하는 GET 요청을 전송하는 함수입니다.
// main.go
func getUser(id string) {
fmt.Println("Getting user by ID...")
// make GET request to API to get user by ID
apiUrl := "https://reqres.in/api/users/" + id
request, error := http.NewRequest("GET", apiUrl, nil)
if error != nil {
fmt.Println(error)
}
request.Header.Set("Content-Type", "application/json; charset=utf-8")
client := &http.Client{}
response, error := client.Do(request)
if error != nil {
fmt.Println(error)
}
responseBody, error := io.ReadAll(response.Body)
if error != nil {
fmt.Println(error)
}
formattedData := formatJSON(responseBody)
fmt.Println("Status: ", response.Status)
fmt.Println("Response body: ", formattedData)
// clean up memory after execution
defer response.Body.Close()
}
GET 요청은 서버에 데이터를 보내지 않으므로 요청 본문을 수락하거나 서버에 보내지 않습니다. 위의 함수에 대한 호출 예시는 다음과 같습니다:
func main() {
fmt.Println("Making GET request...")
getUser("2")
}
출력:
PUT 요청
PUT 요청은 데이터를 서버로 전송하기 때문에 POST 요청과 매우 유사합니다. 가장 큰 차이점은 POST는 새 리소스를 생성하는 반면 PUT는 기존 리소스를 업데이트한다는 점입니다.
다음은 PUT 요청의 구현입니다:
// main.go
func updateUser(name, job, id string) {
fmt.Println("Updating user...")
// make PUT request to API to update user
apiUrl := "https://reqres.in/api/users/" + id
userData := []byte(`{"name":"` + name + `","job":"` + job + `"}`)
// create new http PUT request
request, error := http.NewRequest("PUT", apiUrl, bytes.NewBuffer(userData))
request.Header.Set("Content-Type", "application/json; charset=utf-8")
// Remaining function body from createUser function...
// Make request, get response, and clear memory...
}
이 코드에서 위의 PUT 요청과 POST 요청의 유일한 차이점은 메서드 이름과 URL이라는 것을 알 수 있습니다. PUT을 사용하여 기존 데이터를 업데이트할 때는 요청 URL에 ID를 추가해야 합니다. 이 함수에 대한 샘플 호출은 다음과 같습니다:
func main() {
// update entry with the ID 2.
updateUser("Tim Newname", "Staff Writer", "2")
}
위 코드는 사용자를 업데이트하고 다음과 같은 출력을 생성합니다:
삭제 요청
삭제 요청 메서드를 사용하여 웹 서버에서 삭제 작업을 수행합니다. 삭제 요청은 URI로 식별된 리소스를 삭제합니다. Go의 DELETE 요청은 다음과 같습니다:
func deleteUser(id string) {
fmt.Println("Deleting user...")
// make DELETE request to API to delete user
apiUrl := "https://reqres.in/api/users/" + id
// create new http request
request, error := http.NewRequest("DELETE", apiUrl, nil)
request.Header.Set("Content-Type", "application/json; charset=utf-8")
client := &http.Client{}
response, error := client.Do(request)
if error != nil {
fmt.Println(error)
}
fmt.Println("Status: ", response.Status)
}
DELETE 요청은 본문을 수락하거나 반환하지 않으므로 JSON 요청 및 응답 본문을 파싱하거나 형식을 지정할 필요가 없습니다. 응답은 성공 또는 실패를 나타내는 상태만 반환합니다. 다음은 함수에 대한 샘플 호출과 그 출력의 모습입니다:
func main() {
fmt.Println("Making DELETE request...")
deleteUser("2")
}
출력:
net/http 패키지의 http.Post() 및 http.Get() 메서드를 사용하면 NewRequest() 함수와 Client{} 구조를 사용하여 별도로 요청을 생성하고 만들 필요 없이 직접 POST 및 GET 요청을 할 수 있으므로 시간을 절약할 수 있습니다. 자세한 내용은 net/http 문서 을 참조하세요.
Go 애플리케이션에서 HTTP 요청 만들기
Go의 http 패키지는 Go 애플리케이션에서 HTTP 요청을 하고 응답을 처리하는 데 필요한 모든 것을 제공합니다. 패키지에서 제공하는 함수와 구조를 사용하면 GET, POST, PUT, DELETE 등 다양한 종류의 요청을 생성하고 전송할 수 있습니다.
이를 통해 다른 웹 서비스 및 API와 상호 작용할 수 있는 웹 애플리케이션을 Go로 쉽게 구축할 수 있습니다. Go에서 HTTP 요청을 만드는 데 더 익숙해지는 좋은 방법은 다른 REST API에 요청하는 애플리케이션을 구축하는 것입니다.