til復活
ちょうど各所でAdvent Calendarが始まったタイミングでそういえば今年はアウトプット少なかったので、Advent Calendarという形でなくても今月は毎日何かしらアウトプットできたらと思っていた。 このtilを見返すと断片的な情報でも結構役立つこともあり、まずはここからアウトプット習慣を復活させていく。
goのディレクトリ構成再考
goのディレクトリ構成のベスプラ的なものを考えていた。 ちょうど去年のこの時期くらいに考えていたことだが、改めて考え直す機会があったので。
まずはGoチームから出ているプロジェクトの目的に応じたディレクトリ構成についてのドキュメントが参考になる。 シンプルな構成なのでこれをベースに議論するのが良さそう。 ちなみにgolang-standardsというリポジトリでもディレクトリ構成が定義されていて、いかにもデファクトっぽい名前だがそういうわけではないらしい。 https://github.com/golang-standards/project-layout/issues/117
このドキュメントを元にChatGPTにUserをCreateするAPIを作成するときのディレクトリ構成とサンプルコードを書いてもらった。 わりとシンプルだが、具体的な課題が出ていないうちはこんなかんじから進めてもいいのではないかと思った。
ディレクトリ構成
server.goは必要に応じて追加
project-root/
cmd/
api-server/
main.go
internal/
server/
server.go
handler/
user.go
model/
user.go
db/
db.go
サンプルコード
model/user.go: ユーザーモデルの定義
package model
type User struct {
ID uint `gorm:"primary_key"`
Name string `gorm:"type:varchar(100);"`
Email string `gorm:"type:varchar(100);unique_index"`
}
db/db.go: gormによるデータベース接続の設定
package db
import (
"gorm.io/driver/mysql"
"gorm.io/gorm"
"yourproject/internal/model"
)
type Database struct {
*gorm.DB
}
func NewDatabase(dsn string) (*Database, error) {
db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{})
if err != nil {
return nil, err
}
db.AutoMigrate(&model.User{})
return &Database{db}, nil
}
handler/user.go: ユーザーを作成するAPIハンドラ
package handler
import (
"net/http"
"github.com/labstack/echo/v4"
"yourproject/internal/db"
"yourproject/internal/model"
)
type UserHandler struct {
DB *db.Database
}
func (h *UserHandler) CreateUser(c echo.Context) error {
u := new(model.User)
if err := c.Bind(u); err != nil {
return err
}
if result := h.DB.Create(u); result.Error != nil {
return c.JSON(http.StatusInternalServerError, result.Error)
}
return c.JSON(http.StatusCreated, u)
}
cmd/api-server/main.go: サーバーのエントリーポイントとルーティング設定
package main
import (
"github.com/labstack/echo/v4"
"log"
"yourproject/internal/db"
"yourproject/internal/handler"
)
func main() {
e := echo.New()
database, err := db.NewDatabase("your-database-connection-string")
if err != nil {
log.Fatal(err)
}
userHandler := &handler.UserHandler{DB: database}
e.POST("/users", userHandler.CreateUser)
e.Logger.Fatal(e.Start(":8080"))
}