メタデータを使用すると、シンプルなタグを通じてコード生成を制御および
カスタマイズできます。Meta
関数を使用して、デザイン要素にメタデータを
追加します。
デフォルトでは、Goaはサービスメソッドで使用される型のみを生成します。デザイン で型を定義しても、メソッドのパラメータや結果で参照されていない場合、Goaは その型の生成をスキップします。
"type:generate:force"
メタデータタグはこの動作をオーバーライドします。サービス
名を引数として取り、どのサービスがその型を生成されたコードに含めるべきかを
指定します。サービス名が提供されない場合、その型はすべてのサービスで生成
されます:
var MyType = Type("MyType", func() {
// 未使用でもservice1とservice2で型を強制的に生成
Meta("type:generate:force", "service1", "service2")
Attribute("name", String)
})
var OtherType = Type("OtherType", func() {
// すべてのサービスで型を強制的に生成
Meta("type:generate:force")
Attribute("id", String)
})
パッケージメタデータを使用して、型が生成される場所を制御できます。デフォルト では、型はそれぞれのサービスパッケージで生成されますが、共有パッケージで 生成することもできます。これは、複数のサービスが同じGo構造体を扱う必要がある 場合、例えばビジネスロジックやデータアクセスコードを共有する場合に特に 便利です。型を共有パッケージで生成することで、サービス間で重複する型定義の 変換を避けることができます:
var CommonType = Type("CommonType", func() {
// 共有型パッケージで生成
Meta("struct:pkg:path", "types")
Attribute("id", String)
Attribute("createdAt", String)
})
これにより、以下のような構造が作成されます:
project/
├── gen/
│ └── types/ # 共有型パッケージ
│ └── common_type.go # CommonTypeから生成
types
パッケージは共有型によく使用されますデフォルトでは、Goaは属性名をキャメルケースに変換してフィールド名を生成 します。例えば、“user_id"という名前の属性は、生成される構造体では"UserID"に なります。
Goaはまた、デザイン型からGo型へのデフォルトの型マッピングも提供します:
String
→ string
Int
→ int
Int32
→ int32
Int64
→ int64
Float32
→ float32
Float64
→ float64
Boolean
→ bool
Bytes
→ []byte
Any
→ any
いくつかのメタデータタグを使用して、個々のフィールドをカスタマイズできます:
struct:field:name
: 生成されるフィールド名をオーバーライドstruct:field:type
: 生成されるフィールド型をオーバーライドstruct:tag:*
: カスタム構造体タグを追加以下は、これらを組み合わせた例です:
var Message = Type("Message", func() {
Meta("struct:pkg:path", "types")
Attribute("id", String, func() {
// フィールド名をオーバーライド
Meta("struct:field:name", "ID")
// カスタムMessagePackタグを追加
Meta("struct:tag:msgpack", "id,omitempty")
// カスタム型で型をオーバーライド
Meta("struct:field:type", "bison.ObjectId", "github.com/globalsign/mgo/bson", "bison")
})
})
これにより、以下のようなGo構造体が生成されます:
type Message struct {
ID bison.ObjectId `msgpack:"id,omitempty"`
}
struct:field:type
を使用する場合:
Protocol Buffersを扱う場合、いくつかのメタデータキーを使用して生成される protobufコードをカスタマイズできます:
struct:name:proto
メタデータを使用すると、生成されるprotobufメッセージ名を
オーバーライドできます。デフォルトでは、Goaはデザインから型名を使用します:
var MyType = Type("MyType", func() {
// protobufメッセージ名を"CustomProtoType"に変更
Meta("struct:name:proto", "CustomProtoType")
Field(1, "name", String)
})
struct:field:proto
メタデータを使用すると、生成されるprotobufフィールド型を
オーバーライドできます。これは、よく知られたprotobuf型や他のprotoファイルの
型を扱う場合に特に便利です。最大4つの引数を受け入れます:
var MyType = Type("MyType", func() {
// シンプルな型のオーバーライド
Field(1, "status", Int32, func() {
// デフォルトのsint32からint32に変更
Meta("struct:field:proto", "int32")
})
// Googleのよく知られたタイムスタンプ型を使用
Field(2, "created_at", Timestamp, func() {
Meta("struct:field:proto",
"google.protobuf.Timestamp", // Proto型
"google/protobuf/timestamp.proto", // Protoインポート
"Timestamp", // Go型
"google.golang.org/protobuf/types/known/timestamppb") // Goインポート
})
})
これにより、以下のようなprotobuf定義が生成されます:
import "google/protobuf/timestamp.proto";
message MyType {
int32 status = 1;
google.protobuf.Timestamp created_at = 2;
}
protoc:include
メタデータは、protocコンパイラを呼び出す際に使用される
インポートパスを指定します。APIレベルまたはサービスレベルで設定できます:
var _ = API("calc", func() {
// すべてのサービスのグローバルインポートパス
Meta("protoc:include",
"/usr/include",
"/usr/local/include")
})
var _ = Service("calculator", func() {
// サービス固有のインポートパス
Meta("protoc:include",
"/usr/local/include/google/protobuf")
// ... サービスメソッド ...
})
API定義で設定すると、インポートパスはすべてのサービスに適用されます。サービス で設定すると、パスはそのサービスにのみ適用されます。
struct:field:proto
メタデータは必要なすべての
インポート情報を提供する必要がありますprotoc:include
のインポートパスは、.protoファイルを含むディレクトリを
指している必要がありますOpenAPI仕様の生成とフォーマットを制御します:
var _ = API("MyAPI", func() {
// OpenAPI生成を制御
Meta("openapi:generate", "false")
// JSON出力をフォーマット
Meta("openapi:json:prefix", " ")
Meta("openapi:json:indent", " ")
})
これにより、OpenAPI JSONのフォーマット方法が影響を受けます:
{
"openapi": "3.0.3",
"info": {
"title": "MyAPI",
"version": "1.0"
}
}
いくつかのメタデータキーを使用して、オペレーションと型がOpenAPI仕様で どのように表示されるかをカスタマイズできます:
var _ = Service("calc", func() {
// オペレーション名をオーバーライド
Method("add", func() {
Meta("openapi:operationId", "customAdd")
})
// スキーマ名をオーバーライド
Method("multiply", func() {
Payload(func() {
Meta("openapi:schema:ref", "#/components/schemas/CustomPayload")
})
})
})
OpenAPIセキュリティ定義をカスタマイズできます:
var _ = Service("calc", func() {
// セキュリティスキームをオーバーライド
Security(JWT, func() {
Meta("openapi:security:scheme", "bearer")
Meta("openapi:security:bearerFormat", "JWT")
})
// スコープをカスタマイズ
Method("add", func() {
Security(OAuth2, func() {
Meta("openapi:security:scopes", "read:calc", "write:calc")
})
})
})
OpenAPI仕様に任意の拡張プロパティを追加できます:
var _ = API("MyAPI", func() {
// APIレベルの拡張
Meta("openapi:extension:x-api-id", "123")
Service("calc", func() {
// サービスレベルの拡張
Meta("openapi:extension:x-service-version", "1.0")
Method("add", func() {
// メソッドレベルの拡張
Meta("openapi:extension:x-rate-limit", "100")
})
})
})
x-
プレフィックスで始まる必要がありますメタデータは、Goaのコード生成をカスタマイズするための強力なメカニズムを提供 します。主な使用例は以下の通りです:
型生成の制御
Protocol Bufferのカスタマイズ
OpenAPI仕様の制御
メタデータを効果的に使用することで、生成されるコードをプロジェクトの特定の ニーズに合わせて調整できます。