본문 바로가기
개발/go

Go Tutorial - Go, Gin 으로 RESTful API 개발하기

by hzhzhz 2022. 6. 10.

본 게시글은 Go lang 의 공식 튜토리얼에서 소개되는 RESTful API 개발 가이드를 실습하며 재정리한 글이다.

원문은 아래 링크에서 확인 가능하다.

https://go.dev/doc/tutorial/web-service-gin

 

Tutorial: Developing a RESTful API with Go and Gin - The Go Programming Language

Tutorial: Developing a RESTful API with Go and Gin This tutorial introduces the basics of writing a RESTful web service API with Go and the Gin Web Framework (Gin). You’ll get the most out of this tutorial if you have a basic familiarity with Go and its

go.dev

 

 

----------시작----------

 

 

Design API endpoints 

/albums

 - get : 앨범 리스트를 가져온다. 리턴 타입은 json

 - post : 새로운 앨범 정보를 생성한다. 데이터 포맷은 json

/albums/:id

 - get : 입력한 id 에 해당하는 앨범 정보를 가져온다. 리턴 타입은 json.

 

Create a folder for your code

$ mkdir web-service-gin

$ cd web-service-gin

$ go mod init example/web-service-gin

 => 이 명령어는 모듈 생성을 위한 과정으로, go.mod 파일을 생성한다. 추후 계속 추적할 디펜던시를 관리하는 목록이 적힌 파일이다.

 'example/web-service-gin' 의 위치에 해당하는 텍스트는 모듈의 path로 모듈의 이름을 의미한다. 추후 이 모듈 아래 있는 모듈 경로의 접두사(?prefix) 에 위치하는 이름이다.

 

Create the data

1. main.go 파일을 만든다.

2. main.go 파일 아래에 패키지를 선언해준다.

 package main

3. 'album' 이라는 이름의 구조체를 선언해준다.

type album struct {
	ID     string  `json:"id"`
	Title  string  `json:"title"`
	Artist string  `json:"artist"`
	Price  float64 `json:"price"`
}

4. album 구조체의 메모리 저장용 데이터를 생성한다.

var albums = []album{
    {ID: "1", Title: "Blue Train", Artist: "John Coltrane", Price: 56.99},
    {ID: "2", Title: "Jeru", Artist: "Gerry Mulligan", Price: 17.99},
    {ID: "3", Title: "Sarah Vaughan and Clifford Brown", Artist: "Sarah Vaughan", Price: 39.99},
}

 

Write a handler to return all items

코드를 써보자

1. get /albums 를 위한 펑션을 작성한다.

// getAlbums responds with the list of all albums as JSON.
func getAlbums(c *gin.Context) {
    c.IndentedJSON(http.StatusOK, albums)
}

 - gin.Context 타입의 인자를 받고 있다. 이 녀석은.. 중요하다.

   "... It carries request details, validates and serializes JSON, and more. ..."

 - Context.IntendedJson  를 호출했다. 구조체를 json 으로 serialize 하고 이것을 response 에 담기 위해.

 

2. 핸들러 function 을 endpoint path 에 연결하기 위해 main 펑션을 작성한다.

func main() {
    router := gin.Default()
    router.GET("/albums", getAlbums)

    router.Run("localhost:8080")
}

 - gin router 를 디폴트 옵션으로 초기화 하였다.

 - get 메소드의 /albums 경로에 연결할 function 의 이름을 적어주었다. (여기서, getAlbums라는 이름만 써준다.)

 - Run 명령으로 라우터를 http.Server 에 attach 하고 서버를 시작시킨다.

 

3. main.go 파일의 상단에 import 구문과 사용된 패키지들이 작성되었을 것이다.

4. 파일 저장하고 이제 실행해보자.

 

코드를 실행시켜보자

1. Gin 모듈을 받았으니 디펜던시에 추가해보자

go get .

2. 모듈 실행 (main.go 파일이 있는 위치에서 실행)

go run .

3. 다른 터미널을 하나 열어서 아래와 같이 실행해보자.

curl http://localhost:8080/albums

실행결과

ㅊㅋㅊㅋ done.

 

Write a handler to add a new item

새로운 앨범 추가를 위해 POST 방식의 /albums 를 위한 개발을 할 차례이다.

코드를 써보자

1. post /postAlbums 를 위한 펑션을 작성한다.

func postAlbums(c *gin.Context) {
    var newAlbum album

    // Call BindJSON to bind the received JSON to
    // newAlbum.
    if err := c.BindJSON(&newAlbum); err != nil {
        return
    }

    // Add the new album to the slice.
    albums = append(albums, newAlbum)
    c.IndentedJSON(http.StatusCreated, newAlbum)
}

 - Context.BindJSON 을 사용하여 새로운 request body 를 newAlbum 에 바인딩 시킨다.

 - albums 슬라이스에 newAlbum 을 더해준다.

 - 201 status code 와 새로 추가한 newAlbum 데이터를 리턴값으로 넘겨준다.

 

2. main 펑션에 post /albums 리퀘스트의 라우터를 추가한다.

func main() {
    router := gin.Default()
    router.GET("/albums", getAlbums)
    router.POST("/albums", postAlbums)

    router.Run("localhost:8080")
}

 

코드를 실행시켜보자

1. 혹시 서버가 실행중이면 일단 끈다.

2. 다시 서버를 실행시킨다. (go run .)

3. 다른 터미널에서 아래와 같이 curl 명령을 날려본다 . 그러면 결과가 아래 이어지듯이 나올 것이다. (나와야 정상)

curl http://localhost:8080/albums \
    --include \
    --header "Content-Type: application/json" \
    --request "POST" \
    --data '{"id": "4","title": "The Modern Sound of Betty Carter","artist": "Betty Carter","price": 49.99}'

HTTP/1.1 201 Created
Content-Type: application/json; charset=utf-8
Date: Wed, 02 Jun 2021 00:34:12 GMT
Content-Length: 116

{
    "id": "4",
    "title": "The Modern Sound of Betty Carter",
    "artist": "Betty Carter",
    "price": 49.99
}

4. 제대로 추가 됐는지 확인 차 모든 앨범의 리스트를 보여주는 get /albums 명령을 날려본다.

curl http://localhost:8080/albums \
    --header "Content-Type: application/json" \
    --request "GET"

[
    {
        "id": "1",
        "title": "Blue Train",
        "artist": "John Coltrane",
        "price": 56.99
    },
    {
        "id": "2",
        "title": "Jeru",
        "artist": "Gerry Mulligan",
        "price": 17.99
    },
    {
        "id": "3",
        "title": "Sarah Vaughan and Clifford Brown",
        "artist": "Sarah Vaughan",
        "price": 39.99
    },
    {
        "id": "4",
        "title": "The Modern Sound of Betty Carter",
        "artist": "Betty Carter",
        "price": 49.99
    }
]%

됐다.

 

Write a handler to return a specific item

이제 id 를 입력했을 때 하나씩 조회하는 기능을 개발해보자.

 

코드를 써보자

1. 앨범 정보를 하나씩 갖고올 getAlbumByID 펑션을 개발한다.

func getAlbumByID(c *gin.Context) {
    id := c.Param("id")

    // Loop over the list of albums, looking for
    // an album whose ID value matches the parameter.
    for _, a := range albums {
        if a.ID == id {
            c.IndentedJSON(http.StatusOK, a)
            return
        }
    }
    c.IndentedJSON(http.StatusNotFound, gin.H{"message": "album not found"})
}

2. main 펑션에 get /albums/:id 를 추가한다.

 

코드를 실행시켜보자

curl http://localhost:8080/albums/2
{
    "id": "2",
    "title": "Jeru",
    "artist": "Gerry Mulligan",
    "price": 17.99
}%

잘 나온다.

 

끝.