728x90
반응형
golang으로 http request를 보내거나 개발형, 코딩 테스트(누가 근데 golang쓰긴 하겠냐마는...)를 준비할 때 쓸 수 있는 템플릿입니다.
golang으로 리퀘스트를 보낼 때 json 직렬화, byte string 변환과 같은 과정이 번거로워서 간단하게 구현해보았습니다.
CallAPI함수에 response 타입을 넣고 method, uri, header, body를 명시하면 결과를 리턴하도록 간단하게 net/http 기반으로 외부 라이브러리 없이 구현했습니다.
package main
import (
"bytes"
"encoding/json"
"io"
"net/http"
)
const (
GET = "GET"
POST = "POST"
PUT = "PUT"
DELETE = "DELETE"
)
// API 호출 함수
// T: response type
func CallAPI[T any](method string, uri string, header map[string]string, body interface{}, client *http.Client) (T, error) {
var result T
buff := _createBody(body)
req, err := http.NewRequest(method, uri, buff)
if err != nil {
return result, err
}
for key, value := range header {
req.Header.Add(key, value)
}
err = _send(client, req, &result)
if err != nil {
return result, err
}
return result, nil
}
// request를 받아 클라이언트에 전달하고 결과를 target에 받아옴
func _send[T any](client *http.Client, request *http.Request, target *T) error {
res, err := client.Do(request)
if err != nil {
return err
}
defer res.Body.Close()
body, err := io.ReadAll(res.Body)
if err != nil {
return err
}
json.Unmarshal(body, target)
return nil
}
// post, put 형식의 body를 만들기 위해 구조체를 buffer 형태로 변환
func _createBody(source interface{}) *bytes.Buffer {
pbytes, _ := json.Marshal(source)
buff := bytes.NewBuffer(pbytes)
return buff
}
전체 예시. API 사이트는 https://jsonplaceholder.typicode.com/guide를 참조했습니다.
package main
import (
"bytes"
"encoding/json"
"fmt"
"io"
"net/http"
)
const (
BASE_URL = "https://jsonplaceholder.typicode.com" // API 사용 가이드: https://jsonplaceholder.typicode.com/guide
GET = "GET"
POST = "POST"
PUT = "PUT"
DELETE = "DELETE"
)
// API 호출 함수
// T: response type
func CallAPI[T any](method string, uri string, header map[string]string, body interface{}, client *http.Client) (T, error) {
var result T
buff := _createBody(body)
req, err := http.NewRequest(method, uri, buff)
if err != nil {
return result, err
}
for key, value := range header {
req.Header.Add(key, value)
}
err = _send(client, req, &result)
if err != nil {
return result, err
}
return result, nil
}
// request를 받아 클라이언트에 전달하고 결과를 target에 받아옴
func _send[T any](client *http.Client, request *http.Request, target *T) error {
res, err := client.Do(request)
if err != nil {
return err
}
defer res.Body.Close()
body, err := io.ReadAll(res.Body)
if err != nil {
return err
}
json.Unmarshal(body, target)
return nil
}
// post, put 형식의 body를 만들기 위해 구조체를 buffer 형태로 변환
func _createBody(source interface{}) *bytes.Buffer {
pbytes, _ := json.Marshal(source)
buff := bytes.NewBuffer(pbytes)
return buff
}
type Resource struct {
Id int `json:"id"`
Title string `json:"title"`
Body string `json:"body"`
UserId int `json:"userId"`
}
func main() {
client := &http.Client{}
// get
getResourceUri := BASE_URL + "/posts/1"
getResourceRes, err := CallAPI[Resource](GET, getResourceUri, nil, nil, client)
if err != nil {
fmt.Println("error: ", err)
return
}
fmt.Println(getResourceUri, getResourceRes)
// post
postResourceUri := BASE_URL + "/posts"
postResourceHeader := map[string]string{"Content-Type": "application/json; charset=UTF-8"}
postResourceBody := Resource{Title: "foo", Body: "bar", UserId: 1}
postResourceRes, err := CallAPI[Resource](POST, postResourceUri, postResourceHeader, postResourceBody, client)
if err != nil {
fmt.Println("error: ", err)
return
}
fmt.Println(postResourceUri, postResourceRes)
// put
putResourceUri := BASE_URL + "/posts/1"
putResourceHeader := map[string]string{"Content-Type": "application/json; charset=UTF-8"}
putResourceBody := Resource{Id: 1, Title: "foo", Body: "bar", UserId: 1}
putResourceRes, err := CallAPI[Resource](PUT, putResourceUri, putResourceHeader, putResourceBody, client)
if err != nil {
fmt.Println("error: ", err)
return
}
fmt.Println(putResourceUri, putResourceRes)
// delete
deleteResourceUri := BASE_URL + "/posts/1"
CallAPI[Resource](DELETE, deleteResourceUri, nil, nil, client)
}
728x90
'개발 > 나머지' 카테고리의 다른 글
linuxbrew 자동 설치 스크립트 (0) | 2023.05.10 |
---|---|
golang generic을 이용한 여러 타입 슬라이스로부터 구조체 슬라이스 생성하기 (0) | 2022.10.10 |
댓글