Slide 1

Slide 1 text

Goa Design Design First!

Slide 2

Slide 2 text

Goa Design Wizard Goa Design Wizard 対話的にデザインの作成が可能 ChatGPT Plus が必要

Slide 3

Slide 3 text

Goaとは マイクロサービスを生成するためのGoのフレームワーク ひとつのデザイン(設計)からサービスのひな形とドキュメントを生成 Goのコードとしてのデザイン Goのコード形式を借用 関数や変数などを利用でき、文法エラーなどもチェックできる デザインが Goa の Single Source of Truth (唯一の情報源)

Slide 4

Slide 4 text

トランスポートを統合的に扱う HTTPトランスポートとgRPCトランスポートを統合的に扱う ひとつのデザインから両方、あるいは一方を扱うコードを生成 トランスポート固有の部分はそれぞれに対応した記述が可能 無理矢理共通化する必要はない トランスポートにかかわらず、ビジネスロジックは共通に記述可能

Slide 5

Slide 5 text

ドキュメントの生成 HTTPに対してはOpenAPIドキュメントを生成 OpenAPI v2 / v3 対応 gRPCに対してはProtoBufferファイルを生成 APIを元に生成されるのでデザインとドキュメントが乖離しない ドキュメントに含まれる注釈やサンプルはデザインに記述可能

Slide 6

Slide 6 text

サーバとクライアント デザインを書くとサーバのひな形を生成 同時にサーバにアクセスするためのクライアントも生成

Slide 7

Slide 7 text

APIデザインのサイクル 1. デザインの作成 2. APIデザインのレビュー 3. ビジネスロジックの実装

Slide 8

Slide 8 text

やってみよう

Slide 9

Slide 9 text

準備 Goaをインストール go install goa.design/goa/v3/cmd/goa@v3 Protobufをインストール go install google.golang.org/protobuf/cmd/protoc-gen-go@latest go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest

Slide 10

Slide 10 text

サンプルデザイン github.com/goadesign/examples にデザインのサンプル集があります gonewコマンドでサンプルをひな形としてコピー可能です 今回はbasicサンプルを利用します: gonew github.com/goadesign/examples/basic github.com/ikawaha/basic ( github.com/ikawaha/basic としているところは適宜自分の利用したいパッケージ名に 変更してください)

Slide 11

Slide 11 text

デザインを見てみる

Slide 12

Slide 12 text

API 色々書ける。けど、実は必須ではないので書かなくともよい。 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 multiplying numbers, a goa teaser") // Server describes a single process listening for client requests. The DSL // defines the set of services that the server hosts as well as hosts details. Server("calc", func() { Description("calc hosts the Calculator Service.") // List the services hosted by this server. Services("calc") // List the Hosts and their transport URLs. Host("development", func() { Description("Development hosts.") // Transport specific URLs, supported schemes are: // 'http', 'https', 'grpc' and 'grpcs' with the respective default // ports: 80, 443, 8080, 8443. URI("http://localhost:8000/calc") URI("grpc://localhost:8080") }) Host("production", func() { Description("Production hosts.") // URIs can be parameterized using {param} notation. URI("https://{version}.goa.design/calc") URI("grpcs://{version}.goa.design") // Variable describes a URI variable. Variable("version", String, "API version", func() { // URL parameters must have a default value and/or an // enum validation. Default("v1") }) }) }) })

Slide 13

Slide 13 text

サービス // Service describes a service var _ = Service("calc", func() { Description("The calc service performs operations on numbers") // Method describes a service method (endpoint) Method("multiply", 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", func() { Meta("rpc:tag", "1") }) Field(2, "b", Int, "Right operand") 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("/multiply/{a}/{b}") // Responses use a "200 OK" HTTP status. // The result is encoded in the response body. Response(StatusOK) }) // GRPC describes the gRPC transport mapping. GRPC(func() { // Responses use a "OK" gRPC code. // The result is encoded in the response message. Response(CodeOK) }) }) // Serve the file gen/http/openapi3.json for requests sent to // /openapi.json. Files("/openapi.json", "openapi3.json") })

Slide 14

Slide 14 text

コード生成 ※ 指定するのはファイルパスでなく、パッケージ名であることに注意 gen と example の2つのコマンドがある。 gen ユーザーがタッチしないコードの生成 (毎回破壊&生成) example ユーザーが実装すべきコードの生成(存在する場合は上書きしない) goa gen github.com/ikawaha/basic/design goa example github.com/ikawaha/basic/design 注: gonew でコピーしてきた場合は ./cmd 下と calc.go を削除してから実行する

Slide 15

Slide 15 text

生成されるファイルの構成 サービスごとにサービスのひな形が生成される . ├── calc.go ← サービス(ビジネスロジック)のひな形 ├── cmd │ ├── calc/ ← サーバの参考実装 │ └── calc-cli/ ← 生成されたクライアント ├── design │ └── design.go ← 今回のデザイン └── gen ← デザインで生成されたもの(生成の度に破壊されるので手は入れない) ├── calc/ ├── grpc/ └── http/

Slide 16

Slide 16 text

サービスのひな形(1) package calcapi import ( "context" "log" calc "github.com/ikawaha/basic/gen/calc" ) // calc service example implementation. // The example methods log the requests and return zero values. type calcsrvc struct { logger *log.Logger } // NewCalc returns the calc service implementation. func NewCalc(logger *log.Logger) calc.Service { return &calcsrvc{logger} } // Multiply implements multiply. func (s *calcsrvc) Multiply(ctx context.Context, p *calc.MultiplyPayload) (res int, err error) { s.logger.Print("calc.multiply") return } ※ return p.A * p.B, nil としてやればかけ算の結果が返る

Slide 17

Slide 17 text

サービスのひな形(2) Payload はトランスポート共通なので、デザインの変更の影響を受けづらい Payload は既にバリデーションを通過してきているので、デザインに書いてあるバリデ ーションは保証されている

Slide 18

Slide 18 text

サーバのひな形 生成されるサーバは参考実装なので、好きなように手直ししてほしい(ミドルウエアを設定 したりとか)、ということになっている。とはいえ、もちろんそのままでも動く。

Slide 19

Slide 19 text

型の対応(1) 基本タイプ 対応するGoの型 (HTTP) gRPCの型との対応 Boolean bool bool Int int sint32 Int32 int32 sint32 Int64 int64 sint64

Slide 20

Slide 20 text

型の対応(2) 基本タイプ 対応するGoの型 (HTTP) gRPCの型との対応 UInt uint uint32 UInt32 uint32 uint32 UInt64 uint64 uint64 Float32 float32 float Float64 float64 double

Slide 21

Slide 21 text

型の対応(3) 基本タイプ 対応するGoの型 (HTTP) gRPCの型との対応 String string string Bytes []byte bytes Any any 非対応

Slide 22

Slide 22 text

バリデーション Attribute("name", String, func() { MinLength(8) MaxLength(31) }) バリデーション 対象 説明 MinLength / MaxLength 文字列 文字列長の最小/最大を指定できる Minimum/Maximum 数値 最小値/最大値を指定できる Enum 文字列/数値 値を列挙して指定できる 定型フォーマット 文字列 別記したフォーマットを指定できる

Slide 23

Slide 23 text

定型バリデーション(1) フォーマット 概要 例 FormatDate RFC3339 の日付形 式 1977-06-28 FormatDateTime RFC3339 の日時形 式 2014-06-10T07:31:34Z FormatRFC1123 RFC1123 形式の日時 Sun, 30 Jan 1972 16:17:03 UTC FormatUUID RFC4122 の UUID形 式 76FB876C-96AC-91E7-BD21- B0C2988DDF65

Slide 24

Slide 24 text

定型バリデーション(2) フォーマット 概要 例 FormatEmail RFC5322 のメールアドレス形式 [email protected] FormatHostname RFC1035 のドメイン名 example.com

Slide 25

Slide 25 text

定型バリデーション(3) フォーマット 概要 例 FormatIPv4, FormatIPv6, FormatIP RFC2373 の IPv4, IPv6 形式のアドレス もしくはそのいずれ か 8.8.8.8, 2001:cafe:109f:34d2:d755:da28:b5dc:8f23 FormatURI RFC3986 の URI形 式 github.com/goadesign/goa

Slide 26

Slide 26 text

定型バリデーション(4) フォーマット 概要 例 FormatMAC IEEE 802 形式の MAC-48, EUI-48 or EUI-64 MACアドレス AD-85-EC-C3-95- 9B FormatCIDR RFC4632 もしくは RFC4291 の CIDR 記法の IP アドレス 192.168.100.14/24 FormatRegexp RE2 で定義される正規表現 (ab)

Slide 27

Slide 27 text

定型バリデーション(5) フォーマット 概要 例 FormatJSON JSON 形式のテキス ト '{"name":"example","email":"[email protected]"}'