🔖

Gin & GormでPOST/GETできるようにする

2023/12/15に公開

概要

先日バックエンドとしてインターンに参加したのですが、急遽バックエンドはSupabaseに変更となり、バックエンドを触る機会が無くなってしまいました。せっかくバックエンド挑戦したのに書き方忘れたくない!ということで思い出そうと思ってPOST/GETできるAPIを実装してみたのでまとめます。

構成

  • Gin: GoのWebフレームワーク。現状最速らしい。。?
  • Gorm: GoのORMライブラリ。データベースをオブジェクトで扱うやつ。
  • PostgreSQL: 今後render.comにデプロイすることを見据えてポスグレをチョイス

早速コード書きます。

今回の目標は「POST/GETが動作すること」、「データベースと接続すること」なのでアーキテクチャは一旦無視。main.goに処理を全て書くことにしました。

データベース接続のための環境変数を.envに書きます。

DB_USER=tetsuro
DB_PASSWORD=postgres
DB_HOST=localhost
DB_PORT=5432
DB_NAME=bulletin

ここからmain.goに書いていきます。
まずはTODOアプリのモデルを構造体を定義します。

type Todo struct {
	// KEY - 型 - json内の定義
	ID    string `json:"id"`
	Title string `json:"title"`
}

ここからmain関数です。
データベース接続のため環境変数を読み込みます。

err := godotenv.Load()
	if err != nil {
		log.Fatal("Error loading .env file")
	}

	user := os.Getenv("DB_USER")
	password := os.Getenv("DB_PASSWORD")
	host := os.Getenv("DB_HOST")
	port := os.Getenv("DB_PORT")
	dbName := os.Getenv("DB_NAME")

データベースの接続を行います。

dsn := "host=" + host + " user=" + user + " password=" + password + " dbname=" + dbName + " port=" + port + " sslmode=disable TimeZone=Asia/Tokyo"
	db, err := gorm.Open(postgres.Open(dsn), &gorm.Config{})
	if err != nil {
		panic("failed to connect database")
	}

	db.AutoMigrate(&Todo{})

db.AutoMigrate(&Todo{})と書くことで構造体に合わせてマイグレーションしてくれるようです。

次にrouterを定義しリクエストごとの処理を書きます。

	router := gin.Default() //routerを定義

	router.GET("/ping", func(c *gin.Context) { //接続テスト用
		c.JSON(200, gin.H{
			"message": "pong",
		})
	})

	router.GET("/todos", func(c *gin.Context) { //TODO取得
		var todos []Todo
		db.Find(&todos)
		c.JSON(200, todos)
	})

	router.POST("/todos", func(c *gin.Context) { //TODO追加
		var todo Todo
		c.BindJSON(&todo)
		db.Create(&todo)
		c.JSON(200, todo)
	})

	router.Run() //これでAPIサーバーを起動。引数なしの場合は自動でportが決まる。

コード全体はこのようになります。
main.go

package main

import (
	"log"
	"os"

	"github.com/gin-gonic/gin"
	"github.com/joho/godotenv"
	"gorm.io/driver/postgres"
	"gorm.io/gorm"
)

type Todo struct {
	ID    string `json:"id"`
	Title string `json:"title"`
}

func main() {
	err := godotenv.Load()
	if err != nil {
		log.Fatal("Error loading .env file")
	}

	user := os.Getenv("DB_USER")
	password := os.Getenv("DB_PASSWORD")
	host := os.Getenv("DB_HOST")
	port := os.Getenv("DB_PORT")
	dbName := os.Getenv("DB_NAME")

	dsn := "host=" + host + " user=" + user + " password=" + password + " dbname=" + dbName + " port=" + port + " sslmode=disable TimeZone=Asia/Tokyo"
	db, err := gorm.Open(postgres.Open(dsn), &gorm.Config{})
	if err != nil {
		panic("failed to connect database")
	}

	db.AutoMigrate(&Todo{})

	router := gin.Default()

	router.GET("/ping", func(c *gin.Context) {
		c.JSON(200, gin.H{
			"message": "pong",
		})
	})

	router.GET("/todos", func(c *gin.Context) {
		var todos []Todo
		db.Find(&todos)
		c.JSON(200, todos)
	})

	router.POST("/todos", func(c *gin.Context) {
		var todo Todo
		c.BindJSON(&todo)
		db.Create(&todo)
		c.JSON(200, todo)
	})

	router.Run()
}

CURLコマンドでテスト

go run main.goでローカルでサーバーを立てます。
次にCURLコマンドでテストしてみます。

メッセージを確認するコマンド

curl http://localhost:8080/ping -X GET

TODOを追加するコマンド

curl  curl --json '{"id": "3", "title": "MYTASK"}' http://localhost:8080/todos

TODOを取得するコマンド

curl http://localhost:8080/todos -X GET

もし上手く行かなければポートを確認するなどしてみてください。

感想

データベース接続に結構時間がかかりました。
アーキテクチャを気にせずPOST/GETする程度なら案外簡単に実装できますね。
今度はアーキテクチャを意識して書こうと思います。

Discussion