Go言語におけるコード生成によるバックエンドロジックの簡素化

Go言語におけるコード生成によるバックエンドロジックの簡素化

バックエンド開発では、特にデータベースクエリやAPIサーバーの実装を扱う際に、反復的なボイラープレートコードが多くなりがちです。このコードを手動で記述して維持することは、エラーが発生しやすく、時間がかかります。コード生成(codegen)ツールは、宣言的な仕様から型安全で効率的、かつ保守可能なコードを生成することで、これらのタスクを自動化するのに役立ちます。

この記事では、2つの人気のあるcodegenツールを使用して、Goでのバックエンドロジックを簡素化する方法を探ります:

なぜコード生成を使うのか?

sqlcによるSQLコード生成

sqlcとは?

sqlcは、SQLクエリからGoコードを生成するツールです。.sqlファイルにSQLクエリを記述すると、sqlcはそれらのクエリを型安全なパラメータと結果で実行するGo関数を生成します。

sqlcの使い方

  1. SQLスキーマとクエリを記述します。
  2. sqlc.yamlを設定して、入出力を指定します。
  3. sqlc generateを実行してGoコードを生成します。

シンプルなusersテーブルがあるとします:

-- schema.sql
CREATE TABLE users (
    id SERIAL PRIMARY KEY,
    name TEXT NOT NULL,
    email TEXT UNIQUE NOT NULL
);

そして、メールアドレスでユーザーを取得するクエリ:

-- queries.sql
-- name: GetUserByEmail :one
SELECT id, name, email FROM users WHERE email = $1;

sqlc.yaml設定:

version: "1"
packages:
  - name: "db"
    path: "./db"
    queries: "./queries.sql"
    schema: "./schema.sql"
    engine: "postgresql"

実行:

sqlc generate

これにより、次のようなメソッドを持つGoコードが生成されます:

func (q *Queries) GetUserByEmail(ctx context.Context, email string) (User, error)

バックエンドで次のように使用できます:

user, err := dbQueries.GetUserByEmail(ctx, "alice@example.com")
if err != nil {
    // エラー処理
}
fmt.Println("User:", user.Name)

これにより、手動でのSQL文字列処理や行のスキャンが不要になり、コードがよりクリーンで安全になります。

oapi-codegenによるサーバーコード生成

oapi-codegenとは?

oapi-codegenは、OpenAPI (Swagger) 仕様からGoサーバー(およびクライアント)コードを生成します。インターフェースとリクエスト/レスポンス型を作成するため、ビジネスロジックの実装に集中できます。

oapi-codegenの使い方

  1. OpenAPIのYAMLまたはJSONファイルでAPIを定義します。
  2. oapi-codegenを実行してGoサーバーコードを生成します。
  3. 生成されたインターフェースメソッドを実装します。

シンプルなOpenAPI仕様 api.yaml を考えてみましょう:

openapi: 3.0.0
info:
  title: User API
  version: 1.0.0
paths:
  /users/{email}:
    get:
      summary: Get user by email
      parameters:
        - name: email
          in: path
          required: true
          schema:
            type: string
      responses:
        "200":
          description: User found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/User"
        "404":
          description: User not found
components:
  schemas:
    User:
      type: object
      properties:
        id:
          type: integer
        name:
          type: string
        email:
          type: string

サーバーコードを生成:

oapi-codegen -generate types,server -package api -o api.gen.go api.yaml

これにより以下が生成されます:

GetUsersEmail(ctx context.Context, email string) (api.User, error)

インターフェースを実装:

type ServerImpl struct {
    db *db.Queries
}
 
func (s *ServerImpl) GetUsersEmail(ctx context.Context, email string) (api.User, error) {
    user, err := s.db.GetUserByEmail(ctx, email)
    if err != nil {
        return api.User{}, err
    }
    return api.User{
        Id:    int64(user.ID),
        Name:  user.Name,
        Email: user.Email,
    }, nil
}

サーバーを接続:

router := api.NewRouter(&ServerImpl{db: dbQueries})
http.ListenAndServe(":8080", router)

sqlcとoapi-codegenを組み合わせるメリット

結論

sqlcoapi-codegenを併用することで、データベースアクセスとAPIサーバーコードの生成を自動化し、Goでのバックエンド開発を大幅に簡素化できます。このアプローチにより、ボイラープレートが削減され、安全性が向上し、開発が加速するため、最も重要なこと、つまりアプリケーションのコアロジックに集中できるようになります。

© Melvin Laplanche - All rights reserved.