サービスを新規開発する際に、フロントの開発で必要なAPIをスタブサーバーとしてサクッと作成できれば、と思ったことはないでしょうか?
今回は、swagger-codegenを使ってAPIスキーマからスタブサーバーのコードを自動生成する方法をご紹介します。
スキーマ作成
まず、SwaggerのAPIスキーマをyamlで作成していきます。
今回は公式のサンプルを使用します。
openapi: "3.0.0"
info:
version: 1.0.0
title: Swagger Petstore
license:
name: MIT
servers:
- url: http://petstore.swagger.io/v1
paths:
/pets:
get:
summary: List all pets
operationId: listPets
tags:
- pets
parameters:
- name: limit
in: query
description: How many items to return at one time (max 100)
required: false
schema:
type: integer
format: int32
responses:
'200':
description: A paged array of pets
headers:
x-next:
description: A link to the next page of responses
schema:
type: string
content:
application/json:
schema:
$ref: "#/components/schemas/Pets"
default:
description: unexpected error
content:
application/json:
schema:
$ref: "#/components/schemas/Error"
post:
summary: Create a pet
operationId: createPets
tags:
- pets
responses:
'201':
description: Null response
default:
description: unexpected error
content:
application/json:
schema:
$ref: "#/components/schemas/Error"
/pets/{petId}:
get:
summary: Info for a specific pet
operationId: showPetById
tags:
- pets
parameters:
- name: petId
in: path
required: true
description: The id of the pet to retrieve
schema:
type: string
responses:
'200':
description: Expected response to a valid request
content:
application/json:
schema:
$ref: "#/components/schemas/Pet"
default:
description: unexpected error
content:
application/json:
schema:
$ref: "#/components/schemas/Error"
components:
schemas:
Pet:
type: object
required:
- id
- name
properties:
id:
type: integer
format: int64
name:
type: string
tag:
type: string
Pets:
type: array
items:
$ref: "#/components/schemas/Pet"
Error:
type: object
required:
- code
- message
properties:
code:
type: integer
format: int32
message:
type: string
今回はこちらのスキーマを元にコードの自動生成を行なっていきます。
swagger-Codegenの動作自体はJava環境をローカルで作るのが面倒なので、dockerを実行する形がいいかと思います。
また、今回はswagger2.0ではなく、openapi3.0仕様で書かれているため、swagger-codegen-cli-v3を用いる必要があります。(今後アップデートでv3ではなくても生成できるようになる可能性はあります。)
今回swaggerの生成に用いるのはこちら。cliをdockerで起動します。
https://hub.docker.com/r/swaggerapi/swagger-codegen-cli-v3
コマンドはこんな感じで
docker run --rm -v ${PWD}:/local swaggerapi/swagger-codegen-cli-v3 generate -i /local/swagger/swagger.yaml -l nodejs-server -o /local
言語はGithubページに掲載されているものならなんでも生成できます。
https://github.com/swagger-api/swagger-codegen
個人的には開発で主にGoを使っているので、ここでもGoを選択したいのですがnodeをおすすめします。というのもGoのサーバーだと生成されるコードがスタブサーバーとしては不十分で補完して返り値などを定義する必要があるからです。他にも生成できる言語でも言語によっては不十分なものになってしまうため、注意して生成されるコードを見てください。
#Dockerfile作成
生成したnodejsコードをrunするDockerfileを作成します。
スタブサーバーでとりあえず動けばいいので最低限なものになっています。
FROM node:12
WORKDIR /app
ADD . /app
RUN npm install
RUN npm audit fix
COPY . .
EXPOSE 8080
CMD [ "node", "index.js" ]
これで動作簡単にAPIスキーマから動作させることが可能になりました。
開発の流れとしてはフロントとバックエンドで相談しながらAPIスキーマを作成→スタブサーバー作成→双方で開発を進める→バックエンドの開発が住んだらスタブサーバーと入れ替えるというものになり、スキーマ駆動開発を用いるとより一層開発効率がよくなるのではないかと思います。
さらにこれまでの手順をcircle ci上で行い、スタブ生成を完全自動化させる方法をご紹介します。
GitOpsを用いているため、ECRにImageをデプロイするまでがデプロイとなっております。
また、一度swaggerファイルをダウングレードしている理由は、今回上記で紹介したswagger-codegen-v3ではスキーマのsampleに定義した値をスタブサーバーで返り値として返す機能が携わっていないからになります。もし、sampleの値をスタブサーバーで返したい場合は、下記コードのように一度ダウングレードして生成することをお勧めします。
version: 2.1
orbs:
node: circleci/node@3.0.0
slack: circleci/slack@3.2.0
aws-ecr: circleci/aws-ecr@6.9.0
jobs:
downgrade-swagger-config:
executor: node/default
steps:
- checkout
- run: sudo npm install -g api-spec-converter
- run: api-spec-converter --from=openapi_3 --to=swagger_2 --syntax=yaml swagger/swagger.yaml > swagger2.yaml
- persist_to_workspace:
root: .
paths:
- .
create-stub-server:
build:
machine: true
steps:
- attach_workspace:
at: .
- checkout
- run: docker run --rm -v ${PWD}:/local swaggerapi/swagger-codegen-cli generate -i /local/swagger2.yaml -l nodejs-server -o /local
- persist_to_workspace:
root: .
paths:
- .
deploy:
executor: aws-ecr/default
steps:
- attach_workspace:
at: .
- aws-ecr/build-and-push-image:
dockerfile: build/stub.Dockerfile
repo: stub-player-api
tag: "${CIRCLE_SHA1}"
- slack/status:
failure_message: ":cry: ${CIRCLE_JOB} job has failed"
success_message: ":tada: ${CIRCLE_JOB} job has successed !!"
workflows:
version: 2
deploy-stub-cluster:
jobs:
- downgrade-swagger-config:
filters:
branches:
only: mock
- create-stub-server:
requires:
- downgrade-swagger-config
- deploy:
name: Deploy Stub to DEV Image
context: dev
requires:
- create-stub-server