Skip to content

Goのフォルダ構成

Goの標準的なフォルダ構成ガイド 📂

Section titled “Goの標準的なフォルダ構成ガイド 📂”

Goには厳格なルールはありませんが、プロジェクトのスケーラビリティとメンテナンス性を高めるためのベストプラクティスがコミュニティで共有されています。

大規模なプロジェクトでは、以下のディレクトリ構成が一般的です。

  • cmd/: サーバーやCLIツールなど、実行可能なアプリケーションのエントリーポイントを置きます。各サブディレクトリが独立した実行可能ファイルに対応します。
  • internal/: プロジェクトの内部ロジックを格納します。Goのツールは、このディレクトリ内のコードが外部プロジェクトからインポートされるのを防ぐため、アプリケーションのコアな部分を保護できます。
  • pkg/: 汎用的なヘルパー関数や共通ライブラリなど、他のプロジェクトからも再利用可能な公開コードを置きます。
  • configs/: 環境変数やデータベース接続情報など、アプリケーションの設定ファイルを一元管理します。
  • docs/: API仕様書や設計ドキュメントなど、プロジェクトのドキュメントを格納します。

2. 大規模プロジェクトの構成例

Section titled “2. 大規模プロジェクトの構成例”

プロジェクトの目的(APIか、バッチ処理かなど)に応じて、internal内の構造をさらに細かく分けます。

APIを主体とするプロジェクトでは、**関心事の分離(Separation of Concerns)**を徹底します。

/my-api-project
├── cmd/
│ └── api/
│ └── main.go # サーバー起動コード
├── internal/
│ ├── app/ # アプリケーションのコアロジック
│ │ ├── handler/ # `HTTP`リクエストのハンドラ
│ │ ├── service/ # ビジネスロジック
│ │ └── repository/ # データベース操作
│ └── middleware/ # 認証やロギングなどの共通処理
├── api/
│ ├── openapi/
│ │ └── openapi.yaml # `OpenAPI`定義
│ └── proto/ # `gRPC`の定義ファイル
└── go.mod

複数の実行ファイルがある場合、各プログラムの役割を明確にします。

/my-batch-project
├── cmd/
│ ├── process-data/
│ │ └── main.go # データ処理バッチ
│ └── worker-cli/
│ └── main.go # `CLI`ツール
├── internal/
│ └── core/
│ └── logic.go # 複数の`cmd`で共有されるロジック
├── pkg/
│ └── job/
│ └── job.go # 再利用可能なジョブ処理ライブラリ
└── go.mod

3. サンプルコード: ミドルウェアの追加 (CORS)

Section titled “3. サンプルコード: ミドルウェアの追加 (CORS)”

internal/middleware/cors.goCORS設定を実装し、cmd/api/main.goでミドルウェアとして利用する例です。

package middleware
import (
"net/http"
)
// `CORS`ミドルウェア
func CORS(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// すべてのオリジンからのリクエストを許可
w.Header().Set("Access-Control-Allow-Origin", "*")
// 許可する`HTTP`メソッド
w.Header().Set("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS")
// 許可するヘッダー
w.Header().Set("Access-Control-Allow-Headers", "Content-Type, Authorization")
// `OPTIONS`リクエスト(プリフライトリクエスト)の場合、200を返して終了
if r.Method == "OPTIONS" {
w.WriteHeader(http.StatusOK)
return
}
// 次のハンドラにリクエストを渡す
next.ServeHTTP(w, r)
})
}
package main
import (
"log"
"net/http"
"my-api-project/internal/app/handler"
"my-api-project/internal/middleware"
)
func main() {
// ユーザーハンドラの初期化
userHandler := handler.NewUserHandler()
// ルーターとミドルウェアの設定
router := http.NewServeMux()
router.HandleFunc("/users", userHandler.GetUsers)
// `CORS`ミドルウェアを適用
wrappedRouter := middleware.CORS(router)
log.Println("Server is running on :8080")
log.Fatal(http.ListenAndServe(":8080", wrappedRouter))
}

このように、Goのフォルダ構成は、関心事を分離し、コードをモジュール化することで、大規模なシステム開発を効率的に進めるための鍵となります。

4. テンプレート(templates/)ディレクトリの追加

Section titled “4. テンプレート(templates/)ディレクトリの追加”

Webアプリケーションを構築する場合、HTMLテンプレートを管理するための専用ディレクトリを設けることが一般的です。これにより、ビジネスロジックとビュー(表示)ロジックが分離され、メンテナンス性が向上します。

プロジェクトのルートディレクトリに templates/ を作成します。

/my-web-project
├── cmd/
│ └── webapp/
│ └── main.go
├── internal/
│ ├── app/
│ │ ├── handler/
│ │ └── service/
│ └── templates/ # `HTML`テンプレートの配置場所
│ ├── base.html
│ └── index.html
├── static/ # `CSS`, `JS`, 画像などの静的ファイル
└── go.mod

ハンドラ内でテンプレートをレンダリングする例です。

internal/app/handler/home.go
package handler
import (
"html/template"
"net/http"
)
// `HomePageHandler` はホームページをレンダリングします
func HomePageHandler(w http.ResponseWriter, r *http.Request) {
tmpl, err := template.ParseFiles("internal/templates/index.html", "internal/templates/base.html")
if err != nil {
http.Error(w, "テンプレートの解析に失敗しました", http.StatusInternalServerError)
return
}
tmpl.Execute(w, nil)
}

5. 環境設定(.env)ファイルの管理

Section titled “5. 環境設定(.env)ファイルの管理”

本番環境と開発環境で異なる設定(データベースのURLAPIキーなど)を扱う場合、.envファイルとそれを読み込むロジックを導入することが強く推奨されます。これにより、機密情報をコードベースから分離し、セキュリティを向上させることができます。

プロジェクトのルートディレクトリに .env ファイルを作成します。

/my-api-project
├── .env # 環境変数の設定ファイル
├── cmd/
├── internal/
└── go.mod

環境変数を簡単に読み込むために、go-dotenvviperのようなライブラリを使用すると便利です。

  • インストール: go get github.com/joho/godotenv

  • .env ファイルの作成:

.env
DB_URL=postgres://user:password@localhost:5432/mydb
API_KEY=your-api-key-here
  • 読み込みコードの追加: アプリケーションのエントリーポイント(main.go)で.envファイルを読み込みます。
cmd/api/main.go
package main
import (
"log"
"os"
"github.com/joho/godotenv"
)
func main() {
// `.env`ファイルを読み込む
err := godotenv.Load()
if err != nil {
log.Fatalf("Error loading .env file: %v", err)
}
// 環境変数を取得
dbURL := os.Getenv("DB_URL")
apiKey := os.Getenv("API_KEY")
log.Printf("DB URL: %s, API Key: %s", dbURL, apiKey)
// ... 以降のアプリケーションロジック ...
}

6. ビルドとデプロイのためのスクリプト

Section titled “6. ビルドとデプロイのためのスクリプト”

プロジェクトが複雑になるにつれて、ビルド、テスト、デプロイといった一連の作業を手動で行うのは非効率的になります。Makefileやシェルスクリプトを用意することで、これらの作業を自動化・標準化できます。

プロジェクトのルートディレクトリに Makefile を作成します。

/my-project
├── Makefile # ビルドとデプロイのスクリプト
├── cmd/
└── go.mod

一般的なタスクを定義する例です。

# Makefile
.PHONY: build test run
APP_NAME := my-app
GO_FILES := $(shell find . -name "*.go")
build:
@echo "Building application..."
go build -o $(APP_NAME) ./cmd/api
test:
@echo "Running tests..."
go test ./...
run: build
@echo "Starting application..."
./$(APP_NAME)
clean:
@echo "Cleaning up..."
go clean
rm -f $(APP_NAME)

このMakefileを使用することで、ターミナルでmake buildと実行するだけでビルドが完了し、make runでアプリケーションを実行できるようになります。

これらの追加要素を考慮することで、より堅牢で管理しやすいGoプロジェクトを構築できます。