読者です 読者をやめる 読者になる 読者になる

goa で Type と MediaType を混ぜないでうまく再利用する

golang Go言語 goadesign

概要

goa では レスポンスの形式を MediaType で定義します.一方,Type は Payload の形式などを定義します. MediaType は Type の特殊な形で,Veiw とか Link が増えたやつなので,Type の代わりに使えるんですけど, Type の代わりに使うと振る舞いが微妙に違うことから変なことになったりするので,代わりに使うのはやめておきたいところです.

でも,Payload で使う要素とMediaTypeで使う要素は大体一緒のことが多く,同じ事を何度も書いたりするのはダルいこともありますし, Attribute を流用したいということも多いのではないでしょうか.

Attribute を流用するいくつかの場面,方法について説明したいと思います.

Reference 関数を使う

Reference 関数を使うと,すでに定義済みの Type や MediaType の Attribute を選んで利用することができます.

次のタイプ定義があるとします:

var CreatePayload = Type("CreatePayload", func() {
        Attribute("no", Integer, "Number")
        Attribute("name", String, "Name of thingy", func() {
                MinLength(5)
                MaxLength(256)
                Pattern("^[a-zA-Z]([a-zA-Z ]+)")
        })
})

MediaType で上で定義した CreatePayload を指定することで,CreatePayload の Attribute をそのまま利用できます. 利用するためには,Attribute の名前を指定するだけで大丈夫です.

var MT = MediaType("application/vnd.app.mt", func() {
        Reference(CreatePayload)
        Attributes(func() {
                Attribute("name") // ← ★ ここで指定すると再利用される.再利用されるのは指定されたものだけ.
        })
        View("default", func() {
                Attribute("name")
        })
})

再利用した Attribute は必要に応じて,タイプ,詳細,バリデーションなどを上書きすることもできます.

DefaultMedia が定義されているときはそれを流用できる

var Results = MediaType("vnd.application/goa.results", func() {
    Description("The results of an operation")
    Attributes(func() {
        Attribute("value", Integer, "Results value")
        Attribute("requester", User)                 
    })
    Links(func() {
        Link("requester")
    })
    View("default", func() {
        Attribute("value")    
        Links()               
    })
    View("extended", func() {
        Attribute("value")    
        Attribute("requester")
    })
})

上のような MediaType があるときに,Action 内のパラメータを MediaType で定義されている Attribute で流用できます.

var _ = Resource("Operands", func() {
    DefaultMedia(Results) // ← ここで デフォルト MediaType を指定している
    Action("add", func() {
        Routing(GET("/add/:left/:right"))
        Params(func() {
            Param("left")    // ★ タイプ,詳細などがデフォルト MediaType から流用できる
            Param("right")   // ★
        })
        Response(OK)     
    })
})

一度定義したものをうまく流用して何度も同じものを定義して使うのを避けたいところですね.