# goa メモ
使っている goa は `v3` なので注意
```
mkdir -p HOGEsvc/design
cd HOGEsvc
go mod init
```
edit `design/design.go`
sample
ref. [Design Overview · Goa :: Design first.](https://goa.design/design/overview/)
```go
package design
import . "goa.design/goa/v3/dsl"
// API describes the global properties of the API server.
var _ = API("calc", func() {
Title("Calculator Service")
Description("HTTP service for adding numbers, a goa teaser")
Server("calc", func() {
Host("localhost", func() { URI("http://localhost:8088") })
})
})
// Service describes a service
var _ = Service("calc", func() {
Description("The calc service performs operations on numbers")
// Method describes a service method (endpoint)
Method("add", func() {
// Payload describes the method payload
// Here the payload is an object that consists of two fields
Payload(func() {
// Attribute describes an object field
Attribute("a", Int, "Left operand")
Attribute("b", Int, "Right operand")
// Both attributes must be provided when invoking "add"
Required("a", "b")
})
// Result describes the method result
// Here the result is a simple integer value
Result(Int)
// HTTP describes the HTTP transport mapping
HTTP(func() {
// Requests to the service consist of HTTP GET requests
// The payload fields are encoded as path parameters
GET("/add/{a}/{b}")
// Responses use a "200 OK" HTTP status
// The result is encoded in the response body
Response(StatusOK)
})
})
})
```
* designファイルの記述方法についてわかったこと
* version3を使用しているがかなり後方互換がない感じなのでドキュメントを読む場合はバージョンに気をつける
* オブジェクトのリストをリクエストとして取りたい場合
* `ArrayOf(<OBJECT_NAME>)`を用いる
* リクエストは`[{"name": "hoge0"}, {"name": "hoge1"}]`の形式
* validationは以下のように`ArrayOf`の第2引数に指定する
```
Payload(ArrayOf(RegisterContent, func() {
Required("name")
}))
```
**気になった挙動**
PayloadでJSON Arrayを受け取りたい場合には`ArrayOf`を用いるが、
ref. [· goa :: Design-first API Generation](https://goa.design/reference/goa/design/apidsl/#ArrayOf)
クラス名を直接指定するとメンバー名によってValidationされる気がする。
`RegisterPayload`は定義部分では`"title"`メンバーを定義しているが、
* `ArrayOf(RegisterPayload)`とすると`Required("Title")`と指定する必要がある。(おそらくジェネレートされたクラスのほうが参照される)
* `ArrayOf("RegisterPayload")`とすると`Required("title")`と指定して動作する
ちょっと直感と違うのでissue調べるなり コード追うなりしたい
`Type`の定義内での`Required()`の指定と`ArrayOf()`の第2引数での療法での`Required`指定する必要がある
* `Type`定義内のみ
* validateされない(内部のjsonマーシャルがエラーを吐いてレスポンスがかえらない)
* `ArrayOf`の第2引数のみ
* 型が合わずにエラーになる
```go
...
Method("register", func() {
Payload(ArrayOf("RegisterPayload", func() { // ここで RegisterPayload 変数を指定すると 小文字で指定できない
Required("title") // ここでvalidateを指定する必要がある
}))
Result(String)
HTTP(func() {
POST("/register")
Response(StatusOK)
Response(StatusBadRequest)
})
})
...
var RegisterPayload = Type("RegisterPayload", func(){
Attribute("title", String)
Required("title") // ココにコメントを書いてもvalidateされない
Attribute("body", String)
Attribute("url", String)
Attribute("service_id", String)
Attribute("contents_id", String)
Attribute("system_cd", String)
Attribute("start_datetime", String)
Attribute("end_datetime", String)
})
```
```
# at project root directory
# <YOUR_MODULE_NAME>/design
goa gen <go_module>/design
goa example <go_module>/design
```
* `gen`コマンドで`gen/`以下は更新される
* `example`コマンドでは生成ファイルは更新されない
* `cmd`以下のファイルは`design.go`の変更に依存しない
* `design.go`の変更後は以下の2つのどちらかの対応をする
* プロジェクトルートにある`<SERVICE_NAME>.go`ファイルのみを削除 => `example`
* `<SERVICE_NAME>.go`ファイルを変更に追従するように変更する
* `DateTime`型は`v3`では廃止されており、`String`として受け取り`Format()`で指定する方式らしい
* ref. [dsl - GoDoc](https://godoc.org/goa.design/goa/dsl#Format)
* `ArrayOf`に入れても`DateTime`のバリデーションはされる。
以下サンプル
```
Attribute("end_datetime", String, func() {
Format(*FormatDateTime*)
})
```
**複数のMethodから単一のPayloadを参照すると生成時に同じ構造体が定義されてエラーになる。**
GETの`Payload`で指定したパラメータはほぼ暗黙的にrequiredになるみたい
(`datetime`を定義しているが、URLのどこでも取っていないみたいな状態にすると`BadRequest`が返る)
* **Required のパラメータは実態で Optional なパラメータは参照渡しになるので利用する側は注意**
* **OptionalかつDefault値を決めると値渡しになるので実際はすべて値渡しになるように以下の組み合わせで使う**
* Required => そのまま値渡しになるのでOK
* Optional => デフォルト値を決めておく必要あり