JSONフィールドのカスタムGo型エイリアス

JSONフィールドの強力な型付けのためにGoでカスタム型エイリアスや名前付き型を作成します。enum、カスタムマーシャラー、ドメイン固有型を解説。

Patterns

詳細な説明

より強力なJSON型付けのためのカスタム型

Goではプリミティブに基づいた名前付き型を定義でき、生のstringやintでは提供できない型安全性、カスタムメソッド、ドメインセマンティクスを実現します。

Enum的な型

{
  "id": 1,
  "status": "active",
  "role": "admin",
  "priority": 3
}
type Status string

const (
    StatusActive   Status = "active"
    StatusInactive Status = "inactive"
    StatusPending  Status = "pending"
)

type Role string

const (
    RoleAdmin  Role = "admin"
    RoleEditor Role = "editor"
    RoleViewer Role = "viewer"
)

type Priority int

const (
    PriorityLow    Priority = 1
    PriorityMedium Priority = 2
    PriorityHigh   Priority = 3
)

type Ticket struct {
    ID       int      `json:"id"`
    Status   Status   `json:"status"`
    Role     Role     `json:"role"`
    Priority Priority `json:"priority"`
}

カスタム型が重要な理由

名前付き型は技術的に同じGo型の値の混同を防ぎます:

func AssignTicket(role Role, status Status) { ... }
// StatusをRoleが期待される場所に誤って渡すことはできない

カスタムマーシャリング

特別なシリアライゼーションが必要な型には、json.Marshalerjson.Unmarshaler を実装します:

type Cents int

func (c Cents) MarshalJSON() ([]byte, error) {
    dollars := float64(c) / 100.0
    return json.Marshal(dollars)
}

func (c *Cents) UnmarshalJSON(b []byte) error {
    var dollars float64
    if err := json.Unmarshal(b, &dollars); err != nil {
        return err
    }
    *c = Cents(dollars * 100)
    return nil
}

この型は内部的に整数セントとして金額を保存しますが、JSONでは小数ドルとしてシリアライズします。

アンマーシャル時のバリデーション

カスタム型はアンマーシャリング中に値を検証できます:

func (s *Status) UnmarshalJSON(b []byte) error {
    var str string
    json.Unmarshal(b, &str)
    switch Status(str) {
    case StatusActive, StatusInactive, StatusPending:
        *s = Status(str)
        return nil
    }
    return fmt.Errorf("invalid status: %s", str)
}

これにより、無効なステータス値がシステム内を伝播する代わりに、パース時に拒否されます。

ユースケース

Goでのドメイン駆動設計は、enum、金額値、識別子のカスタム型の恩恵を受けます。コンパイル時にバグをキャッチし、JSON APIデータの変換時にコードを自己文書化します。

試してみる — JSON to Go Struct Converter

フルツールを開く