[Go] Golang으로 REST(CR) API를 만들어보자

Haeun Noh·2024년 3월 20일
0

Go Lang

목록 보기
2/3
post-thumbnail

0320


1. GoLand 세팅

1.1. 폴더 생성

mkdir bin
  • bin 폴더 생성
mkdir pkg
  • pkg 폴더 생성
mkdir src
  • src 폴더 생성

위의 세 폴더 중 소스코드를 보관할 곳은 src입니다.
src안에는 소스를 작성할 main.go파일을 생성해주세요.

package main // package가 main으로 되어 있지 않다면 실행할 수가 없습니다. 

func main() {

}

1.2. go module 등록

cd src
go mod init noah.io/ark/rest

src 폴더로 들어가 go module을 등록합니다.


1.3. 디렉토리 구조

root
├── bin
├── pkg 
├── src
	└── main.go
└── go.mod


2. CR(UD) api 생성

REST APICRUDcreateread의 작업만 하는 REST API를 만들어보겠습니다.


2.1. 서버 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가 잘 출력되는 것을 확인할 수 있습니다.


2.2. 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.Methodget인지 post인지를 판단하여 유저의 정보를 조회하거나 등록할 수 있는 REST API입니다.

만약 request.Methodhttp.MethodGet이라면 users의 정보를 json형태로 변환하여 출력해줄 것입니다.

만약 request.Methodhttp.MethodPost라면 json형식으로 들어온 request를 디코딩하여 user에 정보를 저장할 수 있도록 한 다음,

사용자의 email을 키로 사용하여 user의 정보를 저장한 뒤 다시 json형태로 정보를 인코딩하여 출력해줍니다.
포스트맨으로 실행하면 이렇게 값이 잘 나오는 것을 볼 수 있습니다.



3. middlewareheadercontent-type을 추가하기

그런데 포스트맨의 response가 뭔가 이상합니다.
json형태이나 text로 출력이 되고 있습니다.

이는 header에 있는 content-typeapplication/json을 등록해주지 않았기 때문입니다.
따라서 기본값인 text로 출력되는 것입니다.

이번에는 미들웨어를 활용하여 responseheadercontent-typejson형식으로 추가해보겠습니다.

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() 미들웨어로 요청이 들어온 responseheadercontent-typeapplication/json으로 줌으로써 응답을 json형태로 볼 수 있게 됩니다.

아래는 포스트맨에서 확인한 응답 결과입니다.



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



profile
기록의 힘을 믿는 개발자, 노하은입니다!

0개의 댓글