Swagger-CodegenとCircleCIでスタブサーバー構築のECRデプロイを完全自動化する

サービスを新規開発する際に、フロントの開発で必要なAPIをスタブサーバーとしてサクッと作成できれば、と思ったことはないでしょうか？

今回は、swagger-codegenを使ってAPIスキーマからスタブサーバーのコードを自動生成する方法をご紹介します。

# スキーマ作成
まず、SwaggerのAPIスキーマをyamlで作成していきます。
今回は公式のサンプルを使用します。


```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

コマンドはこんな感じで

```bash
 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を作成します。
スタブサーバーでとりあえず動けばいいので最低限なものになっています。

```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の値をスタブサーバーで返したい場合は、下記コードのように一度ダウングレードして生成することをお勧めします。

```yaml
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
```