GoLand 세팅mkdir bin
mkdir pkg
mkdir src
위의 세 폴더 중 소스코드를 보관할 곳은 src입니다.
src안에는 소스를 작성할 main.go파일을 생성해주세요.
package main // package가 main으로 되어 있지 않다면 실행할 수가 없습니다.
func main() {
}
go module 등록cd src
go mod init noah.io/ark/rest
src 폴더로 들어가 go module을 등록합니다.
root
├── bin
├── pkg
├── src
└── main.go
└── go.mod
CR(UD) api 생성REST API의 CRUD 중 create와 read의 작업만 하는 REST API를 만들어보겠습니다.
routing 해보기package main
import "net/http"
func main() {
http.HandleFunc("/", func(writer http.ResponseWriter, request *http.Request) {
writer.Write([]byte("hello"))
})
http.ListenAndServe(":8000", nil)
}
위의 코드는 go 서버를 localhost:8000에 띄울 수 있게 해줍니다.
http.ListenAndServe(":8000", nil)의 nil이란 값이 없음을 뜻합니다.
ListenAndServe의 두 번째 인수에는 실행할 핸들러를 적는데 값이 nil이기 때문에 맨 마지막에 정의된 핸들러가 실행되게 됩니다.
포스트맨에서 테스트를 하면 hello가 잘 출력되는 것을 확인할 수 있습니다.
Create, Read api 생성package main
import (
"encoding/json"
"net/http"
)
// 사용자의 이메일을 키로 정보를 저장하는 맵입니다.
var users = map[string]*User{}
// User 구조체
// 각각 nickname과 email의 타입이 문자열(string)입니다.
type User struct {
Nickname string `json:"nickname"`
Email string `json:"email"`
}
func main() {
http.HandleFunc("/users", func(writer http.ResponseWriter, request *http.Request) {
switch request.Method {
case http.MethodGet: // 조회
json.NewEncoder(writer).Encode(users) // 인코딩
case http.MethodPost: // 등록
var user User
json.NewDecoder(request.Body).Decode(&user) // 디코딩
users[user.Email] = &user
json.NewEncoder(writer).Encode(user) // 인코딩
}
})
http.ListenAndServe(":8080", nil)
}
위의 코드는 localhost:8000/users의 서버에 들어온 request.Method가 get인지 post인지를 판단하여 유저의 정보를 조회하거나 등록할 수 있는 REST API입니다.
만약 request.Method가 http.MethodGet이라면 users의 정보를 json형태로 변환하여 출력해줄 것입니다.
만약 request.Method가 http.MethodPost라면 json형식으로 들어온 request를 디코딩하여 user에 정보를 저장할 수 있도록 한 다음,
사용자의 email을 키로 사용하여 user의 정보를 저장한 뒤 다시 json형태로 정보를 인코딩하여 출력해줍니다.
포스트맨으로 실행하면 이렇게 값이 잘 나오는 것을 볼 수 있습니다.
middleware로 header에 content-type을 추가하기그런데 포스트맨의 response가 뭔가 이상합니다.
json형태이나 text로 출력이 되고 있습니다.
이는 header에 있는 content-type에 application/json을 등록해주지 않았기 때문입니다.
따라서 기본값인 text로 출력되는 것입니다.
이번에는 미들웨어를 활용하여 response의 header의 content-type을 json형식으로 추가해보겠습니다.
package main
import (
"encoding/json"
"net/http"
)
var users = map[string]*User{}
type User struct {
Nickname string `json:"nickname"`
Email string `json:"email"`
}
// 4. 요청이 들어온 Response Header에 ContentType을 추가하고 전달받은 HandleFunc타입의 함수에 ResponseWriter와 Request를 넘겨줍니다.
// next는 미들웨어의 변수입니다.
func jsonContentTypeMiddleware(next http.Handler) http.Handler {
// 들어오는 요청의 Response Header에 Content-type을 json으로 설정해준다.
return http.HandlerFunc(func(writer http.ResponseWriter, request *http.Request) {
writer.Header().Add("Content-Type", "application/json")
// 전달받은 http.Handler 호출
next.ServeHTTP(writer, request)
})
}
func main() {
// 1. 새로운 mux를 만듭니다.
// mux는 요청 경로와 핸들러를 매핑하는 역할을 합니다.
mux := http.NewServeMux()
// 2. 기존에 만들어놓은 HandleFunc를 HandlerFunc로 변경 ("/users" 삭제)
// 원하는 경로를 함수와 연결시킬 수 있습니다.
userHandler := http.HandlerFunc(func(writer http.ResponseWriter, request *http.Request) {
switch request.Method {
case http.MethodGet: // 조회
json.NewEncoder(writer).Encode(users)
case http.MethodPost: // 삽입
var user User
json.NewDecoder(request.Body).Decode(&user) // 디코딩
users[user.Email] = &user
json.NewEncoder(writer).Encode(user)
}
})
// 3. 만들어놓은 미들웨어에 파라미터로 넘깁니다. ("/users"는 이 때 사용)
mux.Handle("/users", jsonContentTypeMiddleware(userHandler))
http.ListenAndServe(":8000", mux)
}
이렇게 jsonContentTypeMiddleware() 미들웨어로 요청이 들어온 response의 header에 content-type을 application/json으로 줌으로써 응답을 json형태로 볼 수 있게 됩니다.
아래는 포스트맨에서 확인한 응답 결과입니다.

이렇게 간단한 REST API를 만들어보았는데
아무런 db를 연결하지 않아 map을 사용하였지만 다음에는 mongodb를 활용하여 값을 db에 저장해보겠습니다.