Goaは、HTTPリクエストをサービスメソッドにマッピングする強力なルーティングシステムを提供します。このガイドでは以下をカバーします:
Goaでは、ルートはサービス定義内のHTTP
関数を使用してデザインで定義されます。HTTP
関数を使用すると、
サービスメソッドがHTTP経由でどのように公開されるかを指定できます。
基本的な例を示します:
var _ = Service("calculator", func() {
// サービス全体のHTTP設定を定義
HTTP(func() {
// このサービスのすべてのエンドポイントのベースパスを設定
Path("/calculator")
})
Method("add", func() {
// メソッドのペイロードを定義
Payload(func() {
// フィールドの順序が重要 - タグ1が最初
Field(1, "a", Int, "最初のオペランド")
Field(2, "b", Int, "2番目のオペランド")
})
// メソッドの結果を定義
Result(Int)
// HTTPトランスポートを定義
HTTP(func() {
POST("/add") // POST /calculator/addを処理
})
})
})
上記の例は:
Goaは、専用のDSL関数を通じてすべての標準HTTPメソッドをサポートしています:GET
、POST
、PUT
、DELETE
、PATCH
、HEAD
、OPTIONS
、TRACE
。
単一のサービスメソッドで複数のHTTPメソッドやパスを処理できます:
Method("manage_user", func() {
Description("ユーザーの作成または更新")
Payload(User)
Result(User)
HTTP(func() {
POST("/users") // ユーザーの作成
PUT("/users/{user_id}") // 既存ユーザーの更新
Response(StatusOK) // 更新の場合は200
Response(StatusCreated) // 作成の場合は201
})
})
URLパスから動的な値を取得するためにパラメータを使用できます。パスパラメータは中括弧{parameter_name}
を使用して定義され、
自動的にペイロードフィールドにマッピングされます。
Method("get_user", func() {
Description("IDによるユーザーの取得")
Payload(func() {
// user_idフィールドはURLパスから設定される
Field(1, "user_id", String, "URLパスからのユーザーID")
})
Result(User)
HTTP(func() {
GET("/users/{user_id}") // {user_id}をpayload.UserIDにマッピング
})
})
Goaでは、パラメータの型はURLパターンではなく、ペイロード定義で定義されます。URLパターンは、 トランスポート名をペイロードフィールドにマッピングする方法のみを定義します。
プリミティブ型の単純なペイロード
Method("get_user", func() {
// ペイロードがプリミティブ型の場合、パスパラメータに直接マッピング
Payload(String, "ユーザーID")
Result(User)
HTTP(func() {
GET("/users/{user_id}") // user_idの値がペイロードになる
})
})
直接マッピングを使用した構造化ペイロード
Method("get_user", func() {
Payload(func() {
// パラメータの型(Int)はここでペイロードで定義
Field(1, "user_id", Int, "ユーザーID")
})
Result(User)
HTTP(func() {
GET("/users/{user_id}") // payload.UserIDに直接マッピング
})
})
トランスポート名のマッピング
Method("get_user", func() {
Payload(func() {
// 内部フィールド名は"id"
Field(1, "id", Int, "ユーザーID")
})
HTTP(func() {
// URLではuser_idを使用するがpayload.IDにマッピング
GET("/users/{user_id:id}")
})
})
パスパターンの{name:field}
構文は名前のマッピングにのみ使用されます:
name
はURLに表示される名前field
はペイロード内のフィールド名プリミティブペイロードの場合、パスパラメータの値がペイロード全体になります:
Method("download", func() {
// ペイロード全体がファイルパスを表す文字列
Payload(String, "ファイルへのパス")
HTTP(func() {
GET("/files/{*path}") // 取得したパスがペイロードになる
})
}
Method("get_version", func() {
// ペイロードは単純な整数
Payload(Int, "APIバージョン番号")
HTTP(func() {
GET("/api/{version}") // バージョン番号がペイロードになる
})
})
構造化ペイロードを使用する場合、パスパラメータを他のペイロードフィールドと組み合わせることができます:
Method("update_user_profile", func() {
Payload(func() {
// パスパラメータ
Field(1, "id", Int, "ユーザーID")
// ボディフィールド
Field(2, "name", String, "ユーザー名")
Field(3, "email", String, "ユーザーのメールアドレス")
})
HTTP(func() {
PUT("/users/{user_id:id}") // URLのuser_idをpayload.IDにマッピング
Body("name", "email") // これらのフィールドはリクエストボディから取得
})
})
クエリ文字列パラメータはParam
関数を使用して定義され、ペイロードフィールドに対応している必要があります。
デフォルト値とバリデーションルールを設定できます:
Method("list_users", func() {
Description("ページネーション付きユーザー一覧")
Payload(func() {
Field(1, "page", Int, "ページ番号", func() {
Default(1) // デフォルトは1ページ目
Minimum(1) // ページは正の数でなければならない
})
Field(2, "per_page", Int, "1ページあたりの項目数", func() {
Default(20) // デフォルトは20項目
Minimum(1)
Maximum(100) // 最大項目数を制限
})
})
Result(CollectionOf(User))
HTTP(func() {
GET("/users")
// ペイロードフィールドをクエリパラメータにマッピング
Param("page")
Param("per_page")
})
})
柔軟なパスマッチングのために、アスタリスク構文(*path
)を使用して残りのすべてのパスセグメントを取得できます。
取得した値はペイロードで利用可能です:
Method("serve_files", func() {
Description("ディレクトリから静的ファイルを提供")
Payload(func() {
// pathフィールドには/files/以降のすべてのセグメントが含まれる
Field(1, "path", String, "ファイルへのパス")
})
HTTP(func() {
GET("/files/*path") // /files/docs/image.pngなどにマッチ
})
})
リソースを表すには名詞を使用し、HTTPメソッドでアクションを定義します:
HTTP(func() {
// 良い例 - HTTPメソッドがアクションを示す
GET("/articles") // 記事一覧
POST("/articles") // 記事作成
GET("/articles/{id}") // 記事1件取得
PUT("/articles/{id}") // 記事更新
DELETE("/articles/{id}") // 記事削除
// 避けるべき例 - URLにアクションが含まれている
GET("/list-articles")
POST("/create-article")
})
コレクションエンドポイントには複数形の名詞を使用し、一貫性を維持します: