goaのDSLのAttributeについて
2017-07-05 / Go
スニペットづくりのためにコード読んでいて気づいたのでメモ。
v1の方。
Attributeとは
AttributeはView, Type, Attribute, Attributesの中で使える関数で、属性を指定するのに使用する。nested attributeってのがあるらしく、Attributeの中でAttributeが使えるらしいが、よくわからない。
Attributeの引数
ドキュメントによると、Attributeの定義は以下のようになっている。
https://goa.design/reference/goa/design/apidsl/#func-attribute-a-name-apidsl-attribute-a
func Attribute(name string, args ...interface{})
1つ目がAttributeの名前になるstringで、2つ目はinterface{}の可変長引数になっている。
2つ目の可変長引数には何渡しても良いのかというとそうではなくて、実際に使える値のパターンもドキュメントに記載されている。(ちゃんと読んでなかった)
Attribute(name string, dataType DataType, description string, dsl func())
Attribute(name string, dataType DataType, description string)
Attribute(name string, dataType DataType, dsl func())
Attribute(name string, dataType DataType)
Attribute(name string, dsl func()) // dataType is String or Object (if DSL defines child attributes)
Attribute(name string) // dataType is String
Attributeの仲間
DSLとしてAttributeのaliasになっているものがある。
- Param
- Member
- Header
の3つ。
Param
https://goa.design/reference/goa/design/apidsl/#func-param-a-name-apidsl-param-a
func Param(name string, args ...interface{})
Param can be used in: Params
Param is an alias of Attribute.
とのこと。
Member
https://goa.design/reference/goa/design/apidsl/#func-member-a-name-apidsl-member-a
func Member(name string, args ...interface{})
Member can be used in: Payload
Member is an alias of Attribute.
とのこと。
Header
https://goa.design/reference/goa/design/apidsl/#func-header-a-name-apidsl-header-a
func Header(name string, args ...interface{})
Headerだけちょっと異なっている。
Header can be used in: Headers, APIKeySecurity, JWTSecurity
Header is an alias of Attribute for the most part.
Within an APIKeySecurity or JWTSecurity definition, Header defines that an implementation must check the given header to get the API Key. In this case, no args parameter is necessary.
APIKeySecurity, JWTSecurityと使う場合には、 args
を指定してはいけないとのこと。
こういう利用のされ方になる。
JWTSecurity("jwt", func() {
Header("Authorization")
TokenURL("<a href="https://example.com/token">https://example.com/token</a>")
Scope("my_system:write", "Write to the system")
Scope("my_system:read", "Read anything in there")
})
コードを確認
ParamとMember
// Member is an alias of Attribute.
func Member(name string, args ...interface{}) {
Attribute(name, args...)
}
// Param is an alias of Attribute.
func Param(name string, args ...interface{}) {
Attribute(name, args...)
}
ParamとMemberは内部でAttributeを呼んでいるだけ。
Header
func Header(name string, args ...interface{}) {
if _, ok := dslengine.CurrentDefinition().(*design.SecuritySchemeDefinition); ok {
if len(args) != 0 {
dslengine.ReportError("do not specify args")
return
}
inHeader(name)
return
}
Attribute(name, args...)
}
Headerは処理中のデザイン定義を表す dslengine.CurrentDefinition
が、 *design.SecuritySchemeDefinition
(APIKeySecurity or JWTSecurity) だった場合には args
の長さをチェックして、0だったらinHeader
を呼び出して終了する。
inHeader
はどのヘッダーにAPIキーが指定されているかを設定する処理。
*design.SecuritySchemeDefinition
ではなければ、そのまま Attribute
を呼び出す。
感想
まとめは特にないので、感想書いとく。
汎用的な関数を作るときの名前って大事だけど、今回のような、Attribute、Param、Memberの総称とか簡単に思いつかない。aliasという形で別名にして提供するってのは良いやり方だと思った。
ドキュメントもちゃんと読むだけじゃなくて、コードも合わせて確認すると理解度が高まる。調べようと思っていたこと以外にも、参考になることがある。
ところで、スニペットの進捗はあまり進んでない。来週とかかな…