Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Go APIを生成するSwagger駆動開発 on AWS Fargate / Swagger...

Go APIを生成するSwagger駆動開発 on AWS Fargate / Swagger-Driven Development Generating Go APIs on AWS Fargate

Go Conference'20 in Autumn SENDAI (2020-10-10) で登壇した資料です。

Swagger 定義から Go の API を生成し、AWS Fargate 上で動かす開発フローを紹介しています。

Avatar for shiro seike

shiro seike PRO

October 10, 2020

More Decks by shiro seike

Other Decks in Programming

Transcript

  1. 自己紹介:清家 史郎 - ID - - 清家 史郎 @seike460 GitHub:seike460

    Twitter:@seike460 Work at - 株式会社 Fusic (フュージック) 技術開発本部/技術開発第一部門 - チームリーダー/エバンジェリスト/プリンシパルエンジニア - Skill - - PHP/Go/AWS Personal - Go Conference ‘19 Summer in Fukuoka コアスタッフ - Fukuoka.go オーガナイザー 46fm パーソナリティ 2
  2. Swagger and OpenAPIの違い OpenAPI:仕様 Swagger:仕様を実装するためのツール ただし OpenAPI Specification v2.0の事を Swagger

    Specification、Swaggerファイルと呼ぶことがあります 参考:What Is the Difference Between Swagger and OpenAPI? 10
  3. go-swagger 注意点としては Swagger 2.0 ≒ OpenAPI Specification v2.0に 相当するツールであるということ 技術選定をする責任は

    選定した本人にあるので OpenAPI Specification v3.0に対する 移行する可能性も視野に入れたかった 17
  4. 実際のSwagger swagger: "2.0" host: "petstore.swagger.io" basePath: "/v2" tags: - name:

    "pet" description: "Everything about your Pets" externalDocs: description: "Find out more" url: "http://swagger.io" schemes: - "https" paths: /pet: post: tags: - "pet" summary: "Add a new pet to the store" Swagger をYAMLで記述 Swagger Editorを利用して チェックを行いながら記述する事は可能 一方で形式を覚える事にコスト感を感じていた 20
  5. go-swagger go-swaggerにて型定義されたコードの自動生成 $ swagger generate server -f doc/swagger/hoge.v1.yaml -t hoge/

    2020/09/30 06:53:25 validating spec /Users/seike460/src/github.com/fusic/hoge/doc/swagger/hoge.v1.yaml 2020/09/30 06:53:25 preprocessing spec with option: minimal flattening 2020/09/30 06:53:25 building a plan for generation 2020/09/30 06:53:25 generation target hoge/ 2020/09/30 06:53:25 planning definitions 2020/09/30 06:53:25 planning operations 2020/09/30 06:53:25 grouping operations into packages 2020/09/30 06:53:25 planning meta data and facades ~ 省略 ~ 2020/09/30 06:53:26 package field operations 2020/09/30 06:53:26 creating generated file "doc.go" in "hoge/restapi" as doc 2020/09/30 06:53:26 executed template asset:serverDoc 2020/09/30 06:53:26 Generation completed! For this generation to compile you need to have some packages in your GOPATH: * github.com/go-openapi/runtime * github.com/jessevdk/go-flags You can get these now with: go get -u -f hoge/... 23
  6. ディレクトリ構成 ├── cmd │ └── hoge-server │ └── main.go ├──

    models │ └── tag.go └── restapi ├── configure_hoge.go ├── doc.go ├── embedded_spec.go ├── operations │ ├── hoge_api.go │ └── tags │ ├── delete_tag.go │ ├── delete_tag_parameters.go │ ├── delete_tag_responses.go │ ├── delete_tag_urlbuilder.go │ ├── get_tags.go │ ├── get_tags_parameters.go │ ├── get_tags_responses.go │ ├── get_tags_urlbuilder.go │ ├── patch_tag.go │ ├── patch_tag_parameters.go │ ├── patch_tag_responses.go │ ├── patch_tag_urlbuilder.go │ ├── post_tags.go │ ├── post_tags_parameters.go │ ├── post_tags_responses.go │ └── post_tags_urlbuilder.go └── server.go cmd … サーバー起動コマンド models … modelの定義 restapi … operationsの定義 configure_hoge.goを修正していくのが一般的 24
  7. configure_hoge_ext.go - restapi/configure_hoge.go api.ServerShutdown = func() {} configureAPIExt(api) return setupGlobalMiddleware(api.Serve(setupMiddlewares))

    - restapi/configure_hoge_ext.go func configureAPIExt(api *operations.HogeAPI) { api.SetHandlers() } Goがパッケージ拡張出来る事を利用して自動生成するコードを別ファイルにて拡張 「configure_hoge.go」を何度も自動生成しても辛くないようにした。 今回の場合、 Handlerは視認性の観点から別管理にしたいと考えた為、 api.SetHandlers()の様に拡張を行い、別ファイルにて HandlerのSetを行った。 ※これが正しいやり方なのかは確証があるわけではありませんのでご注意ください 27
  8. models ├── cmd │ └── hoge-server │ └── main.go ├──

    models │ └── tag.go └── restapi ├── configure_hoge.go ├── doc.go ├── embedded_spec.go ├── operations │ ├── hoge_api.go │ └── tags │ ├── delete_tag.go │ ├── delete_tag_parameters.go │ ├── delete_tag_responses.go │ ├── delete_tag_urlbuilder.go │ ├── get_tags.go │ ├── get_tags_parameters.go │ ├── get_tags_responses.go │ ├── get_tags_urlbuilder.go │ ├── patch_tag.go │ ├── patch_tag_parameters.go │ ├── patch_tag_responses.go │ ├── patch_tag_urlbuilder.go │ ├── post_tags.go │ ├── post_tags_parameters.go │ ├── post_tags_responses.go │ └── post_tags_urlbuilder.go └── server.go Modelが生成されるディレクトリ ここにHandler内で利用するModelが入っている modelsも再生成される事を考慮して拡張する 28
  9. OpenAPI Generator OpenAPI Generator Swagger形式で記述されたYAMLやJSONから コード生成してくれるOSS(OpenAPI Specification V3にも対応) $ openapi-generator

    generate -g typescript-axios -i doc/swagger/hoge.v1.yaml -o frontend/src/api [main] INFO o.o.codegen.DefaultGenerator - Generating with dryRun=false [main] INFO o.o.codegen.DefaultGenerator - OpenAPI Generator: typescript-axios (client) [main] INFO o.o.codegen.DefaultGenerator - Generator 'typescript-axios' is considered stable. [main] INFO o.o.c.l.AbstractTypeScriptClientCodegen - Hint: Environment variable 'TS_POST_PROCESS_FILE' (optional) not defined. E.g. to format the source code, please try 'export TS_POST_PROCESS_FILE="/usr/local/bin/prettier --write"' (Linux/Mac) [main] INFO o.o.c.l.AbstractTypeScriptClientCodegen - Note: To enable file post-processing, 'enablePostProcessFile' must be set to `true` (--enable-post-process-file for CLI). [main] INFO o.o.codegen.AbstractGenerator - writing file /Users/seike460/src/github.com/fusic/hoge/frontend/src/api/index.ts [main] INFO o.o.codegen.AbstractGenerator - writing file /Users/seike460/src/github.com/fusic/hoge/frontend/src/api/base.ts [main] INFO o.o.codegen.AbstractGenerator - writing file /Users/seike460/src/github.com/fusic/hoge/frontend/src/api/api.ts [main] INFO o.o.codegen.AbstractGenerator - writing file /Users/seike460/src/github.com/fusic/hoge/frontend/src/api/configuration.ts [main] INFO o.o.codegen.AbstractGenerator - writing file /Users/seike460/src/github.com/fusic/hoge/frontend/src/api/git_push.sh [main] INFO o.o.codegen.AbstractGenerator - writing file /Users/seike460/src/github.com/fusic/hoge/frontend/src/api/.gitignore [main] INFO o.o.codegen.AbstractGenerator - writing file /Users/seike460/src/github.com/fusic/hoge/frontend/src/api/.npmignore [main] INFO o.o.codegen.AbstractGenerator - writing file /Users/seike460/src/github.com/fusic/hoge/frontend/src/api/.openapi-generator/VERSION 34
  10. OpenAPI Generator ✕ TypeScript OpenAPI Generator ✕ TypeScriptでカッチリ型定義を行いながら開発することで 定まったコードを生成し、細かなミスを排除する →ビジネスロジックに集中する

    →コードの質とスピードを加速させる import { DefaultApi, Tag } from "../api/api"; ~ 省略 ~ const api = new DefaultApi(); ~ 省略 ~ const searchTags = (keyword: string) => { api .getTags(keyword) .then((res) => { setTags(res.data); }) .catch((err) => { alert(err.message); // エラー処理が甘いことはこの場では目をつぶってください }); }; 35
  11. マルチステージビルド ビルドと、ビルドしたバイナリを利用するコンテナを分離 ビルドに必要なGoが入っていないalpineにバイナリを配置 -> 最小のコンテナサイズで実行ファイルが利用可能 ※利用OSに注意 FROM golang:1.15.2 as build

    WORKDIR /go/src COPY . . RUN CGO_ENABLED=0 go build -o hoge-server cmd/hoge-server/main.go FROM alpine:edge WORKDIR /root/ COPY --from=build /go/src/hoge-server . CMD ["./hoge-server", "--host", "0.0.0.0", "--port", "80"] 38
  12. AWS CodeBuild 今回 AWS Fargateを利用する為、ECRにPushしておく必要がある CodePipeline でGitHubよりコード取得 -> CodeBuildを通してECRにPushする version:

    0.2 phases: pre_build: commands: - $(aws ecr get-login --no-include-email --region ap-northeast-1) build: commands: - docker build -t $IMAGE_REPO_NAME:$IMAGE_TAG --build-arg BUILDSTAGE=$BUILDSTAGE . - echo docker tag $IMAGE_REPO_NAME:$IMAGE_TAG $AWS_ACCOUNT_ID.dkr.ecr.$AWS_DEFAULT_REGION.amazonaws.com/$IMAGE_REPO_NAME:$IMAGE_TAG - docker tag $IMAGE_REPO_NAME:$IMAGE_TAG $AWS_ACCOUNT_ID.dkr.ecr.$AWS_DEFAULT_REGION.amazonaws.com/$IMAGE_REPO_NAME:$IMAGE_TAG post_build: commands: - echo Build completed on `date` - echo Pushing the Docker image... - docker push $AWS_ACCOUNT_ID.dkr.ecr.$AWS_DEFAULT_REGION.amazonaws.com/$IMAGE_REPO_NAME:$IMAGE_TAG - printf '[{"name":"<container-definition>","imageUri":"%s"}]' $AWS_ACCOUNT_ID.dkr.ecr.$AWS_DEFAULT_REGION.amazonaws.com/$IMAGE_REPO_NAME:$IMAGE_TAG > artifacts.json 41
  13. まとめ Point 1 SPAを作る上でのフロントエンドとバックエンドとの連携をSwaggerで決めて開発を進める Point 2 Go API を 構築するにあたり、コード生成を行いインターフェイス部分をgo-swaggerに任せる

    合わせてGo APIへの接続はOpenAPI generator x TypeScriptに任せて、ビジネスロジックに集中する Point 3 Go のビジネスロジック部分の構築は生成されたコードをパッケージ拡張して構築する Point 4 AWS FargateへのデプロイはECRに配置して利用する マルチステージビルドでGoの利点を活かし、小さなコンテナサイズで実現 42