Go 언어로 API 서버 만들기

까망새부리·2023년 3월 20일
1
post-thumbnail

발단

Hyperledger Fabric의 Chaincode를 개발할 상황이 생기면서 Go언어를 사용할 일이 생겼다.
한 번쯤 배우고 싶었던 언어이고 필요성이 생긴 만큼 간단한 API 서버 개발을 통해 Go언어에 익숙해지기 위해서 간단한 API 서버를 개발해봤다.

진행 과정

개발 환경 구축

사전 준비

개발 과정

model 설정

package model

type Message struct {
	ID  string `json:"id"`
	Msg string `json:"msg"`
}

DB에 저장하기 위한 데이터 형태를 선언한 부분이다. 데이터는 ID 값과 메시지 값을 저장할 수 있게 선언했다.

db 연결 부분

package db

import (
	"database/sql"
	"fmt"

	model "example.com/practice/model"
	_ "github.com/lib/pq"
)

const (
	host     = "localhost"
	port     = 5432
	user     = "postgres"
	password = "postgres"
	dbname   = "postgres"
)

func connect() *sql.DB {
	psqlInfo := fmt.Sprintf("host=%s port=%d user=%s "+
		"password=%s dbname=%s sslmode=disable",
		host, port, user, password, dbname)

	dbcon, err := sql.Open("postgres", psqlInfo)

	if err != nil || dbcon.Ping() != nil {
		panic(err.Error())
	}

	return dbcon
}

func GetMessage(id string) []model.Message {
	db := connect()
	selectDynStmt := `SELECT id, msg FROM Message where "id"=$1`
	rows, err := db.Query(selectDynStmt, id)

	messages := []model.Message{}

	checkError(err)
	defer db.Close()
	defer rows.Close()

	for rows.Next() {
		var msg model.Message
		if err := rows.Scan(&msg.ID, &msg.Msg); err != nil {
			panic(err)
		}

		messages = append(messages, msg)
	}

	return messages
}

func SaveMessage(msg model.Message) sql.Result {
	db := connect()
	if db.Ping() != nil {
		panic(db.Ping().Error())
	}
	insertDynStmt := `insert into Message ("id", "msg") values($1, $2)`
	result, err := db.Exec(insertDynStmt, msg.ID, msg.Msg)
	checkError(err)
	defer db.Close()
	return result
}

func UpdateMessage(msg model.Message) sql.Result {
	db := connect()
	if db.Ping() != nil {
		panic(db.Ping().Error())
	}

	updateDynStmt := `update Message set "msg"=$1 where "id"=$2`
	result, err := db.Exec(updateDynStmt, msg.Msg, msg.ID)

	checkError(err)
	defer db.Close()

	return result
}

func DeleteMessage(id string) sql.Result {
	db := connect()
	if db.Ping() != nil {
		panic(db.Ping().Error())
	}

	deleteDynStmt := `delete from Message where "id"=$1`
	result, err := db.Exec(deleteDynStmt, id)
	checkError(err)

	defer db.Close()

	return result
}

func checkError(err error) {
	if err != nil {
		panic(err)
	}

}

PostgreSQL과 연결하고 간단한 CRUD 작업을 하는 부분입니다.

routing 설정

package router

import (
	"log"
	"net/http"

	db "example.com/practice/db"
	model "example.com/practice/model"
	"github.com/gin-gonic/gin"
)

func StartRouter() {
	router := gin.Default()

	router.GET("/message/:id", func(c *gin.Context) {
		id := c.Param("id")
		result := db.GetMessage(id)
		c.IndentedJSON(http.StatusOK, result)
	})

	router.POST("/message", func(c *gin.Context) {
		var newMessage model.Message

		if err := c.BindJSON(&newMessage); err != nil {
			log.Fatal("BIND JSON ERROR")
			return
		}

		result := db.SaveMessage(newMessage)
		c.IndentedJSON(http.StatusCreated, result)
	})

	router.PUT("/message", func(c *gin.Context) {
		var updateMessage model.Message

		if err := c.BindJSON(&updateMessage); err != nil {
			log.Fatal("BIND JSON ERROR")
			return
		}

		result := db.UpdateMessage(updateMessage)
		c.IndentedJSON(http.StatusAccepted, result)
	})

	router.DELETE("/message", func(c *gin.Context) {
		var deleteMessage model.Message

		if err := c.BindJSON(&deleteMessage); err != nil {
			log.Fatal("BIND JSON ERROR")
			return
		}

		result := db.DeleteMessage(deleteMessage.ID)
		c.IndentedJSON(http.StatusAccepted, result)
	})

	router.Run("localhost:8080")
}

간단한 REST API를 routing 하는 부분입니다.

참고

profile
배움을 찾는 사람이 되자!

0개의 댓글