Go ์–ธ์–ด๋Š” ์†๋„์™€ ์•ˆ์ •์„ฑ, ๊ทธ๋ฆฌ๊ณ  ๋‹จ์ผ ๋ฐ”์ด๋„ˆ๋ฆฌ ๋ฐฐํฌ์˜ ๊ฐ„ํŽธํ•จ ๋•๋ถ„์—
์ตœ๊ทผ ๋ฐฑ์—”๋“œ, ๋งˆ์ดํฌ๋กœ์„œ๋น„์Šค, DevOps ๋„๊ตฌ ๊ฐœ๋ฐœ์— ๋งค์šฐ ์ž์ฃผ ์‚ฌ์šฉ๋˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

์ด๋ฒˆ ๊ธ€์—์„œ๋Š” Go๋กœ ๊ฐ„๋‹จํ•œ JSON ๊ธฐ๋ฐ˜ REST API ์„œ๋ฒ„๋ฅผ ์ง์ ‘ ๋งŒ๋“ค์–ด๋ณด๋ฉฐ,
Go์˜ HTTP ์ฒ˜๋ฆฌ ๊ตฌ์กฐ์™€ JSON ์ง๋ ฌํ™”/์—ญ์ง๋ ฌํ™”(Serialization/Deserialization)๋ฅผ ์ดํ•ดํ•ด๋ด…๋‹ˆ๋‹ค.


๐Ÿงฐ 1. ํ”„๋กœ์ ํŠธ ์ดˆ๊ธฐ ์„ค์ •

๋จผ์ € Go ํ”„๋กœ์ ํŠธ๋ฅผ ์ดˆ๊ธฐํ™”ํ•ฉ๋‹ˆ๋‹ค.

mkdir go-rest-api
cd go-rest-api
go mod init example.com/go-rest-api

go.mod ํŒŒ์ผ์ด ์ƒ์„ฑ๋ฉ๋‹ˆ๋‹ค.
Go์˜ ์˜์กด์„ฑ ๊ด€๋ฆฌ ์‹œ์Šคํ…œ(go mod)์€ Node์˜ package.json๊ณผ ๋น„์Šทํ•œ ์—ญํ• ์„ ํ•ฉ๋‹ˆ๋‹ค.


โš™๏ธ 2. ๋ฉ”์ธ ์„œ๋ฒ„ ํŒŒ์ผ ์ƒ์„ฑ

main.go ํŒŒ์ผ์„ ์ƒ์„ฑํ•˜๊ณ , ๊ฐ€์žฅ ๊ธฐ๋ณธ์ ์ธ HTTP ์„œ๋ฒ„๋ฅผ ๊ตฌ์„ฑํ•ฉ๋‹ˆ๋‹ค.

package main

import (
    "encoding/json"
    "log"
    "net/http"
)

type User struct {
    ID    int    `json:"id"`
    Name  string `json:"name"`
    Email string `json:"email"`
}

var users = []User{
    {ID: 1, Name: "Heejune", Email: "hee@example.com"},
    {ID: 2, Name: "Jihyun", Email: "jihyun@example.com"},
}

func main() {
    http.HandleFunc("/users", getUsersHandler)

    log.Println("โœ… Server started on port 8080")
    log.Fatal(http.ListenAndServe(":8080", nil))
}

func getUsersHandler(w http.ResponseWriter, r *http.Request) {
    w.Header().Set("Content-Type", "application/json")
    json.NewEncoder(w).Encode(users)
}

๐Ÿงฉ ์ฝ”๋“œ ์„ค๋ช…

  • http.HandleFunc : ์š”์ฒญ ๊ฒฝ๋กœ(/users)์™€ ํ•ธ๋“ค๋Ÿฌ๋ฅผ ๋งคํ•‘
  • json.NewEncoder(w).Encode(users) : ๊ตฌ์กฐ์ฒด ๋ฐฐ์—ด์„ JSON์œผ๋กœ ๋ณ€ํ™˜ํ•ด ์‘๋‹ต
  • ListenAndServe(":8080", nil) : 8080 ํฌํŠธ๋กœ HTTP ์„œ๋ฒ„ ์‹คํ–‰

์ด์ œ ์‹คํ–‰ํ•ด ๋ด…์‹œ๋‹ค.

go run main.go

๋ธŒ๋ผ์šฐ์ €๋‚˜ Postman์—์„œ http://localhost:8080/users ๋กœ ์ ‘์†ํ•˜๋ฉด ๐Ÿ‘‡

[
  { "id": 1, "name": "Heejune", "email": "hee@example.com" },
  { "id": 2, "name": "Jihyun", "email": "jihyun@example.com" }
]


๐Ÿงพ 3. POST ์š”์ฒญ์œผ๋กœ JSON ๋ฐ›๊ธฐ

์ด๋ฒˆ์—” ์ƒˆ๋กœ์šด ์œ ์ €๋ฅผ ์ถ”๊ฐ€ํ•˜๋Š” POST /users API๋ฅผ ์ถ”๊ฐ€ํ•ด๋ด…์‹œ๋‹ค.

func createUserHandler(w http.ResponseWriter, r *http.Request) {
    if r.Method != http.MethodPost {
        http.Error(w, "Invalid request method", http.StatusMethodNotAllowed)
        return
    }

    var newUser User
    if err := json.NewDecoder(r.Body).Decode(&newUser); err != nil {
        http.Error(w, err.Error(), http.StatusBadRequest)
        return
    }

    newUser.ID = len(users) + 1
    users = append(users, newUser)

    w.Header().Set("Content-Type", "application/json")
    w.WriteHeader(http.StatusCreated)
    json.NewEncoder(w).Encode(newUser)
}

๊ทธ๋ฆฌ๊ณ  ๋ผ์šฐํ„ฐ์— ์ถ”๊ฐ€ํ•ฉ๋‹ˆ๋‹ค.

func main() {
    http.HandleFunc("/users", func(w http.ResponseWriter, r *http.Request) {
        switch r.Method {
        case http.MethodGet:
            getUsersHandler(w, r)
        case http.MethodPost:
            createUserHandler(w, r)
        default:
            http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
        }
    })

    log.Println("โœ… Server started on port 8080")
    log.Fatal(http.ListenAndServe(":8080", nil))
}

์ด์ œ POST /users ๋กœ ์•„๋ž˜ JSON์„ ์ „์†กํ•˜๋ฉด ์ƒˆ๋กœ์šด ์œ ์ €๊ฐ€ ์ถ”๊ฐ€๋ฉ๋‹ˆ๋‹ค.

{
  "name": "Siyu",
  "email": "siyu@example.com"
}


๐Ÿงฑ 4. Clean Architecture ๊ตฌ์กฐ๋กœ ๊ฐœ์„ ํ•˜๊ธฐ

์‹ค๋ฌด์—์„œ๋Š” ์ฝ”๋“œ๊ฐ€ ์ ์  ์ปค์ง€๊ธฐ ๋•Œ๋ฌธ์— ํ•ธ๋“ค๋Ÿฌ, ์„œ๋น„์Šค, ๋ชจ๋ธ, ๋ผ์šฐํ„ฐ๋ฅผ ๋ถ„๋ฆฌํ•ฉ๋‹ˆ๋‹ค.
ํด๋” ๊ตฌ์กฐ๋ฅผ ์•„๋ž˜์ฒ˜๋Ÿผ ๋ณ€๊ฒฝํ•ด๋ณด์„ธ์š” ๐Ÿ‘‡

go-rest-api/
โ”œโ”€โ”€ main.go
โ”œโ”€โ”€ handler/
โ”‚   โ””โ”€โ”€ user_handler.go
โ”œโ”€โ”€ model/
โ”‚   โ””โ”€โ”€ user.go
โ”œโ”€โ”€ service/
โ”‚   โ””โ”€โ”€ user_service.go

model/user.go

package model

type User struct {
    ID    int    `json:"id"`
    Name  string `json:"name"`
    Email string `json:"email"`
}


service/user_service.go

package service

import "example.com/go-rest-api/model"

var users = []model.User{
    {ID: 1, Name: "Heejune", Email: "hee@example.com"},
    {ID: 2, Name: "Jihyun", Email: "jihyun@example.com"},
}

func GetAllUsers() []model.User {
    return users
}

func AddUser(u model.User) model.User {
    u.ID = len(users) + 1
    users = append(users, u)
    return u
}


handler/user_handler.go

package handler

import (
    "encoding/json"
    "net/http"

    "example.com/go-rest-api/model"
    "example.com/go-rest-api/service"
)

func GetUsersHandler(w http.ResponseWriter, r *http.Request) {
    w.Header().Set("Content-Type", "application/json")
    json.NewEncoder(w).Encode(service.GetAllUsers())
}

func CreateUserHandler(w http.ResponseWriter, r *http.Request) {
    if r.Method != http.MethodPost {
        http.Error(w, "Method Not Allowed", http.StatusMethodNotAllowed)
        return
    }

    var user model.User
    if err := json.NewDecoder(r.Body).Decode(&user); err != nil {
        http.Error(w, err.Error(), http.StatusBadRequest)
        return
    }

    created := service.AddUser(user)
    w.Header().Set("Content-Type", "application/json")
    w.WriteHeader(http.StatusCreated)
    json.NewEncoder(w).Encode(created)
}


main.go

package main

import (
    "log"
    "net/http"

    "example.com/go-rest-api/handler"
)

func main() {
    http.HandleFunc("/users", func(w http.ResponseWriter, r *http.Request) {
        switch r.Method {
        case http.MethodGet:
            handler.GetUsersHandler(w, r)
        case http.MethodPost:
            handler.CreateUserHandler(w, r)
        default:
            http.Error(w, "Method Not Allowed", http.StatusMethodNotAllowed)
        }
    })

    log.Println("๐Ÿš€ Go REST API Server started on port 8080")
    log.Fatal(http.ListenAndServe(":8080", nil))
}

์ด์ œ ๊ตฌ์กฐ๊ฐ€ ๊น”๋”ํ•ด์กŒ์Šต๋‹ˆ๋‹ค!
ํ•ธ๋“ค๋Ÿฌ โ†’ ์„œ๋น„์Šค โ†’ ๋ชจ๋ธ ์ˆœ์œผ๋กœ ์—ญํ• ์ด ๋ถ„๋ฆฌ๋˜์–ด ์œ ์ง€๋ณด์ˆ˜๊ฐ€ ํ›จ์”ฌ ์‰ฌ์›Œ์ง‘๋‹ˆ๋‹ค.


๐Ÿ”ฅ 5. ์‹คํ–‰ ๋ฐ ํ…Œ์ŠคํŠธ

go run main.go

GET ์š”์ฒญ

curl http://localhost:8080/users

POST ์š”์ฒญ

curl -X POST -H "Content-Type: application/json" \
-d '{"name":"Chihyun","email":"chi@example.com"}' \
http://localhost:8080/users


๐Ÿงฉ 6. Go์˜ JSON ์ฒ˜๋ฆฌ ํŠน์ง• ์š”์•ฝ

ํ•ญ๋ชฉ์„ค๋ช…
์ง๋ ฌํ™”json.Marshal() ์‚ฌ์šฉ
์—ญ์ง๋ ฌํ™”json.Unmarshal() ์‚ฌ์šฉ
๊ตฌ์กฐ์ฒด ํƒœ๊ทธjson:"name" ์œผ๋กœ ํ‚ค ๋งคํ•‘
์ž๋™ ๋ณ€ํ™˜JSON์˜ ์ˆซ์ž๋Š” float64๋กœ ์ธ์‹
์˜ค๋ฅ˜ ์ฒ˜๋ฆฌ๋ช…์‹œ์  if err != nil ๋กœ ์˜ˆ์™ธ ๊ด€๋ฆฌ

Go๋Š” Python๋ณด๋‹ค ๋‹ค์†Œ ๋ณต์žกํ•˜์ง€๋งŒ,
๊ทธ๋งŒํผ ํƒ€์ž… ์•ˆ์ •์„ฑ์ด ๊ฐ•๋ ฅํ•˜๊ณ  ์„ฑ๋Šฅ์ด ๋น ๋ฅด๋ฉฐ,
๋Œ€๊ทœ๋ชจ ์„œ๋น„์Šค์—์„œ๋„ ์˜ˆ์ธก ๊ฐ€๋Šฅํ•œ ๋™์ž‘์„ ๋ณด์žฅํ•ฉ๋‹ˆ๋‹ค.


โœ… 7. ๋งˆ๋ฌด๋ฆฌ

์ด๋ฒˆ ํŠœํ† ๋ฆฌ์–ผ์—์„œ๋Š”

  • Go์˜ ๊ธฐ๋ณธ HTTP ์„œ๋ฒ„ ๊ตฌ์ถ•
  • JSON ์š”์ฒญ/์‘๋‹ต ์ฒ˜๋ฆฌ
  • Clean Architecture ๊ตฌ์กฐํ™”
    ๋ฅผ ๋ชจ๋‘ ๋‹ค๋ค„๋ดค์Šต๋‹ˆ๋‹ค.

์ด์ œ ์—ฌ๊ธฐ์„œ ํ™•์žฅํ•ด๋ณด์„ธ์š” ๐Ÿ‘‡

  • /users/{id} โ†’ ๊ฐœ๋ณ„ ์กฐํšŒ API
  • PUT / DELETE โ†’ ์ˆ˜์ • ๋ฐ ์‚ญ์ œ ๊ธฐ๋Šฅ
  • gorilla/mux ๊ฐ™์€ ๋ผ์šฐํ„ฐ ํ”„๋ ˆ์ž„์›Œํฌ ๋„์ž…
  • PostgreSQL, MySQL ์—ฐ๋™์œผ๋กœ ์‹ค์„œ๋น„์Šค ์ˆ˜์ค€ ๊ฐ•ํ™”
Posted in

๋Œ“๊ธ€ ๋‚จ๊ธฐ๊ธฐ