データモデリング
Goaは、ドメインを正確かつ明確にモデル化できる強力な型システムを提供します。 シンプルなプリミティブ型から複雑なネスト構造まで、DSLはデータの関係、制約、 バリデーションルールを自然な方法で表現する手段を提供します。
基本型
Goaの型システムの基礎は、プリミティブ型と基本的な型定義から始まります。これらの 構成要素により、シンプルながらも表現力豊かなデータ構造を作成できます。
プリミティブ型
Goaは、すべてのデータモデリングの基礎となる豊富な組み込みプリミティブ型を提供します:
Boolean // JSONブール値
Int // 符号付き整数
Int32 // 符号付き32ビット整数
Int64 // 符号付き64ビット整数
UInt // 符号なし整数
UInt32 // 符号なし32ビット整数
UInt64 // 符号なし64ビット整数
Float32 // 32ビット浮動小数点数
Float64 // 64ビット浮動小数点数
String // JSON文字列
Bytes // バイナリデータ
Any // 任意のJSON値
型定義
Type DSL関数は、構造化されたデータ型を定義する主要な方法です。属性、バリデーション、 ドキュメントをサポートします:
var Person = Type("Person", func() {
Description("人物")
// 基本的な属性
Attribute("name", String)
// バリデーション付きの属性
Attribute("age", Int32, func() {
Minimum(0)
Maximum(120)
})
// 必須フィールド
Required("name", "age")
})
複合型
実世界のドメインをモデル化する際には、より洗練されたデータ構造が必要になることが よくあります。Goaはコレクションとネスト型に対する包括的なサポートを提供します。
配列
配列を使用すると、任意の型の順序付きコレクションをオプションのバリデーションルール 付きで定義できます:
var Names = ArrayOf(String, func() {
// 配列要素のバリデーション
MinLength(1)
MaxLength(10)
})
var Team = Type("Team", func() {
Attribute("members", ArrayOf(Person))
})
マップ
マップは、キーと値の両方に対する型安全性とバリデーションを備えたキーと値の関連付けを 提供します:
var Config = MapOf(String, Int32, func() {
// キーのバリデーション
Key(func() {
Pattern("^[a-z]+$")
})
// 値のバリデーション
Elem(func() {
Minimum(0)
})
})
型の合成
Goaは、コードの再利用と関心事の明確な分離を可能にする洗練された型の合成パターンを サポートします。
Reference
Referenceを使用すると、別の型から属性のデフォルトプロパティを設定できます。現在の型の 属性が参照される型の属性と同じ名前を持つ場合、参照される属性のプロパティを継承します。 複数の参照を指定でき、プロパティは出現順に検索されます:
var Employee = Type("Employee", func() {
// Personから属性定義を再利用
Reference(Person)
Attribute("name") // name属性を再定義する必要なし
Attribute("age") // age属性を再定義する必要なし
// 新しい属性を追加
Attribute("employeeID", String, func() {
Format(FormatUUID)
})
})
Extend
Extendは既存の型に基づいて新しい型を作成し、階層的な関係のモデル化に最適です。
Referenceとは異なり、Extendは自動的にベース型からすべての属性を継承します。
var Manager = Type("Manager", func() {
// ベース型を拡張
Extend(Employee)
// マネージャー固有のフィールドを追加
Attribute("reports", ArrayOf(Employee))
})
バリデーションルール
Goaは、データの整合性を確保しビジネスルールを強制するための包括的なバリデーション 機能を提供します。以下がGoaで利用可能な主要なバリデーションルールです:
文字列のバリデーション
Pattern(regex)- 正規表現に対するバリデーションMinLength(n)- 最小文字列長MaxLength(n)- 最大文字列長Format(format)- 事前定義されたフォーマット(メール、URI等)に対するバリデーション
数値のバリデーション
Minimum(n)- 最小値(含む)Maximum(n)- 最大値(含む)ExclusiveMinimum(n)- 最小値(含まない)ExclusiveMaximum(n)- 最大値(含まない)
配列とマップのバリデーション
MinLength(n)- 最小要素数MaxLength(n)- 最大要素数
オブジェクトのバリデーション
Required("field1", "field2")- 必須フィールド
汎用バリデーション
Enum(value1, value2)- 列挙された値に制限
さらに、配列とマップの要素は、属性と同じルールを使用してバリデーションできます。
バリデーションルールを組み合わせて、包括的なバリデーションロジックを作成できます:
var UserProfile = Type("UserProfile", func() {
Attribute("username", String, func() {
Pattern("^[a-z0-9]+$") // 正規表現パターン
MinLength(3) // 最小文字列長
MaxLength(50) // 最大文字列長
})
Attribute("email", String, func() {
Format(FormatEmail) // 組み込みフォーマット
})
Attribute("age", Int32, func() {
Minimum(18) // 最小値
ExclusiveMaximum(150) // 最大値(含まない)
})
Attribute("tags", ArrayOf(String, func() { Enum("tag1", "tag2", "tag3") }), func() {
// 配列要素の列挙値
MinLength(1) // 最小配列長
MaxLength(10) // 最大配列長
})
Attribute("settings", MapOf(String, String), func() {
MaxLength(20) // 最大マップ長
})
Required("username", "email", "age") // 必須フィールド
})
カスタム型
ドメイン固有のフォーマットとバリデーションルールをカプセル化する再利用可能な カスタム型を作成します:
// カスタムフォーマットを定義
var UUID = Type("UUID", String, func() {
Format(FormatUUID)
Description("RFC 4122 UUID")
})
// カスタム型を使用
var Resource = Type("Resource", func() {
Attribute("id", UUID)
Attribute("name", String)
})
詳細についてはType DSLを参照してください。
組み込みフォーマット
Goaには、一般的なデータパターン用の包括的な事前定義フォーマットが含まれています。 これらのフォーマットは自動バリデーションと明確な意味を提供します:
FormatDate- RFC3339日付値FormatDateTime- RFC3339日時値FormatUUID- RFC4122 UUID値FormatEmail- RFC5322メールアドレスFormatHostname- RFC1035インターネットホスト名FormatIPv4- RFC2373 IPv4アドレス値FormatIPv6- RFC2373 IPv6アドレス値FormatIP- RFC2373 IPv4またはIPv6アドレス値FormatURI- RFC3986 URI値FormatMAC- IEEE 802 MAC-48、EUI-48またはEUI-64 MACアドレス値FormatCIDR- RFC4632およびRFC4291 CIDR表記IPアドレス値FormatRegexp- RE2で受け入れられる正規表現構文FormatJSON- JSONテキストFormatRFC1123- RFC1123日時値
Attribute vs Field DSL
Goaは型の属性を定義する2つの同等の方法を提供します:AttributeとFieldです。
主な違いは、FieldがgRPCメッセージのフィールド番号に使用される追加のタグパラメータを
取ることです。
Attribute DSL
gRPCサポートが不要な場合や、gRPCメッセージで使用されない型を定義する場合に使用します:
var Person = Type("Person", func() {
Attribute("name", String)
Attribute("age", Int32)
})
Field DSL
gRPCメッセージで使用される型を定義する場合に使用します。最初の引数はフィールド番号 タグです:
var Person = Type("Person", func() {
Field(1, "name", String)
Field(2, "age", Int32)
})