Skip to content

traP-jp/circuledge-backend

Repository files navigation

go-backend-template

xc compatible

ハッカソンなど短期間でWebアプリを開発する際のバックエンドのGo実装例です。 学習コストと開発コストを抑えることを目的としています。

How to use

GitHubの Use this template ボタンからレポジトリを作成します。

gonew コマンドからでも作成できます。gonew コマンドを使うと、モジュール名を予め変更した状態でプロジェクトを作成することができます。

gonew github.com/ras0q/go-backend-template {{ project_name }}

Requirements

最低限DockerDocker Composeが必要です。 Compose Watchを使うため、Docker Composeのバージョンは2.22以上にしてください。

Linter, Formatterにはgolangci-lintを使っています。 VSCodeを使用する場合は.vscode/settings.jsonでLinterの設定を行ってください

{
  "go.lintTool": "golangci-lint"
}

Tasks

開発に用いるコマンド一覧

Tip

xc を使うことでこれらのコマンドを簡単に実行できます。 詳細は以下のページをご覧ください。

go install github.com/joerdav/xc/cmd/xc@latest

Build

アプリをビルドします。

CMD=server
go mod download
go build -o ./bin/${CMD} ./cmd/${CMD}

Dev

ホットリロードの開発環境を構築します。

docker compose watch

API、DB、DB管理画面が起動します。 各コンテナが起動したら、以下のURLにアクセスすることができます。 Compose Watchにより、ソースコードの変更を検知して自動で再起動します。

Test

全てのテストを実行します。

go test -v -cover -race -shuffle=on ./...

Test-Unit

単体テストを実行します。

go test -v -cover -race -shuffle=on ./internal/...

Test-Integration

結合テストを実行します。

[ ! -e ./go.work ] && go work init . ./integration_tests
go test -v -cover -race -shuffle=on ./integration_tests/...

Test-Integration:Update

結合テストのスナップショットを更新します。

[ ! -e ./go.work ] && go work init . ./integration_tests
go test -v -cover -race -shuffle=on ./integration_tests/... -update

Lint

Linter (golangci-lint) を実行します。

golangci-lint run --timeout=5m --fix ./...

Directory structure

Organizing a Go module - The Go Programming Language などを参考にしています。

$ tree -d
.
├── bin # ビルドしたバイナリ
├── cmd # エントリーポイント
│   └── server # サーバーのエントリーポイント (main.goを置く)
│       └── server # サーバー固有の設定
├── integration_tests # 結合テスト
├── internal # アプリケーション本体のロジック
│   ├── handler # ルーティング
│   └── repository # DBアクセス
└── pkg # 汎用パッケージ
    ├── config # アプリ・DBの設定
    └── database # DBの初期化、マイグレーション
        └── migrations # DBマイグレーションのスキーマ

12 directories

特に重要なものは以下の通りです。

cmd/

アプリケーションのエントリーポイントを配置します。 エントリーポイントは複数のアプリケーションを持つことも可能です。

テンプレートではサーバーのエントリーポイントがcmd/server/main.goに配置されています。 cmd/server/server/ にはDIやヘルスチェックなど、サーバー固有の設定を書いています。

internal/

アプリケーション本体のロジックを配置します。 主に2つのパッケージに分かれています。

  • handler/: ルーティング
    • 飛んできたリクエストを裁いてレスポンスを生成する
    • DBアクセスはrepository/で実装したメソッドを呼び出す
    • Tips: リクエストのバリデーションがしたい場合は↓のどちらかを使うと良い
  • repository/: ストレージ操作
    • DBや外部ストレージなどのストレージにアクセスする
      • 引数のバリデーションはhandler/に任せる

Tips: internalパッケージは他モジュールから参照されません(参考: Go 1.4 Release Notes)。 依存性注入や外部ライブラリの初期化のみをcmd/pkgで公開し、アプリケーションのロジックはinternal/に閉じることで、後述のintegration_tests/go.modなどの外部モジュールからの参照を最小限にすることができ、開発の効率を上げることができます。

pkg/

汎用的なパッケージを配置します。

  • config/: アプリ・DBの設定
    • 環境変数を読み込むためのパッケージ
  • database/: DBの初期化、マイグレーション
    • DBのスキーマを定義する
    • Tips: マイグレーションツールはpressly/gooseを使っている

integration_tests/

結合テストを配置します。 APIエンドポイントに対してリクエストを送り、レスポンスを検証します。 短期開発段階では時間があれば書く程度で良いですが、長期開発に向けては書いておくと良いでしょう。

package integration_tests

import (
  "testing"
  "gotest.tools/v3/assert"
)

func TestUser(t *testing.T) {
  t.Run("get users", func(t *testing.T) {
    t.Run("success", func(t *testing.T) {
      t.Parallel()
      rec := doRequest(t, "GET", "/api/v1/users", "")

      expectedStatus := `200 OK`
      expectedBody := `[{"id":"[UUID]","name":"test","email":"[email protected]"}]`
      assert.Equal(t, rec.Result().Status, expectedStatus)
      assert.Equal(t, escapeSnapshot(t, rec.Body.String()), expectedBody)
    })
  })
}

Tips: DBコンテナの立ち上げにはory/dockertestを使っています。

Tips: アサーションにはgotest.toolsを使っています。 go test -updateを実行することで、expectedXXXのスナップショットを更新することができます(参考: gotest.toolsを使う - 詩と創作・思索のひろば)。

外部サービス(traQ, Twitterなど)へのアクセスが発生する場合はTest Doublesでアクセスを置き換えると良いでしょう。

Improvements

長期開発に向けた改善点をいくつか挙げておきます。

  • ドメインを書く (internal/domain/など)
    • 現在は簡単のためにAPIスキーマとDBスキーマのみを書きこれらを直接やり取りしている
    • 本来はアプリの仕様や概念をドメインとして書き、スキーマの変換にはドメインを経由させるべき
  • クライアントAPIスキーマを共通化させる
    • OpenAPIやGraphQLを使い、そこからGoのファイルを生成する
  • 単体テスト・結合テストのカバレッジを上げる
    • カバレッジの可視化にはCodecov(traPだと主流)やCoverallsが便利
  • ログの出力を整備する
    • ロギングライブラリは好みに合ったものを使うと良い

About

No description, website, or topics provided.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Contributors 6