OpenAPI + Docker + Nuxt + TypeScriptで快適な開発環境を - inokawablog

OpenAPI + Docker + Nuxt + TypeScriptで快適な開発環境を

プロダクトを作っていく時に、仕様に関する情報をしっかり作っておくことで、新しくプロジェクトに加わる人に、細かく仕様を説明する必要がなくなります。さらにフロントエンドとバックエンドが共通の仕様を見ることで、認識の齟齬が少なくなり開発効率を最大化することができます。そのためにもOpenAPIを使用してAPIの設計書を作成しておきます。

OpenAPIを使用するメリットは以下が挙げられます。

  • APIを指定のフォーマットで規定できる
  • ファイルがAPIドキュメントになる
  • API定義からサーバやクライアントのコード生成ができる

OpenAPIとは

OpenAPIは、Web APIの仕様を形式的に記述するためのフォーマットのことです。APIの設計書みたいなものです。

OpenAPI generator

openapi-generatorOpenAPI Specificationをベースにして様々なクライアントやサーバのコードを自動で生成できます。

基本的な言語には対応しています。

今回はNuxtで使用するであろうtypescript-axiosのコードを自動で生成します。

作成手順

Nuxtを使用している場合、予めsrc/typesを作成しておいてください。

openapi-generatorが自動でファイルを生成して保存する先をsrc/typesにするためです。

APIの定義ファイルの作成

まず、APIの定義するためのopenapi.ymlの内容は以下のようにして作成してください。

openapi.yml

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

こちらの内容に関しては、こちらを参考に作成しています。

そして、openapi.ymlと同じディレクトリにdocker-compose.ymlを作成します。

docker-compose.yml

version: '3'
services:
  # https://github.com/openapitools/openapi-generator-cli
  openapi-generator:
    image: openapitools/openapi-generator-cli
    volumes:
      - ./:/app
    command: generate -g typescript-axios -i /app/openapi.yml -o /app/src/types/typescript-axios

openapi-generatorのDocker Imageがすでに用意されているのでそれを使用しています。

以下コマンドを実行することでsrc/types以下にtypescript-axiosというフォルダが自動で生成され、その中に型のファイルが自動で生成されます。

$ docker-compose up -d openapi-generator

Swagger UI

API仕様の自動作成までできたので、次はドキュメントを作成していきます。

ドキュメント作成にはswagger-uiを使用します。
個人的にデザインがあまり好きではないですが笑。

こちらもすでにDocker Imageが用意されているのでそれを使用します。

docker-compose.ymlに以下の内容を追記してください。

version: '3'
services:
  # https://swagger.io/tools/swagger-ui/
  swagger-ui:
    image: swaggerapi/swagger-ui
    volumes:
      - ./openapi.yml:/app/openapi.yml
    environment:
      SWAGGER_JSON: /app/openapi.yml
    ports:
      - 8080:8080

または、以下でも簡単に使うことができます。

$ docker run --rm -p 8080:8080 -e SWAGGER_JSON=/app/openapi.yml -v ${PWD}:/app swaggerapi/swagger-ui

http://localhost:8080 にアクセスすると見れるようになっていると思います。

スタブサーバを作成

開発をしていると簡単にAPIを試したくなる時があります。そのために、openapi.yamlのAPIをモックするためのスタブサーバを生成します。

今回はprismを使用します。

Stoplightが開発しており、StoplightはStoplight StudioというAPI仕様を記載するためのGUIエディタを作成しています。
これがとても使いやすく簡単に素早くAPI仕様を記述することができます。Swagger Editorはもう必要ないと思います。

docker-compose.ymlに以下を追記

version: '3'
services:
  # https://stoplight.io/p/docs/gh/stoplightio/prism
  mock-api:
    image: stoplight/prism
    volumes:
      - ./openapi.yml:/app/openapi.yml
    ports:
      - 4010:4010
    # -dをつけることでランダムなデータが返ってくる
    command: mock -h 0.0.0.0 -d /app/openapi.yml

そして以下のコマンドを実行

$ docker-compose up -d mock-api

スタブサーバーが立ち上がったかどうか確認するにはcurlでURLを叩いてみましょう。

$ curl -s -X GET "http://localhost:4010/pets"

ランダムなデータが返ってきたら成功です。

実際にNuxtで使用する場合は、以下のようになります。

const response = await $axios.get('http://localhost:4010/pets')
console.log(response)

最終的なdocker-compose.ymlは以下になります。

version: '3'
services:
  # https://github.com/openapitools/openapi-generator-cli
  openapi-generator:
    image: openapitools/openapi-generator-cli
    volumes:
      - ./:/app
    command: generate -g typescript-axios -i /app/openapi.yml -o /app/src/types/typescript-axios
  # https://swagger.io/tools/swagger-ui/
  swagger-ui:
    image: swaggerapi/swagger-ui
    volumes:
      - ./openapi.yml:/app/openapi.yml
    environment:
      SWAGGER_JSON: /app/openapi.yml
    ports:
      - 8080:8080
  # https://stoplight.io/p/docs/gh/stoplightio/prism
  mock-api:
    image: stoplight/prism
    volumes:
      - ./openapi.yml:/app/openapi.yml
    ports:
      - 4010:4010
    # -dをつけることでランダムなデータが返ってくる
    command: mock -h 0.0.0.0 -d /app/openapi.yml

スキーマの分解

APIが増えていくにつれてopenapi.ymlが肥大化していくのが容易に想像がつきます。
そのためにスキーマの分解が必要です。

OpenAPI generatorの方はうまく分解したファイルを参照できるのですが、swagger UIでは参照がされない(そういう仕様なのかな)ので、現在調査中です。

参考

※現在調査中なので、完了次第追記します。

まとめ

導入してみると結構開発が楽になるので是非使ってみてください。

参考

OpenAPIとTypeScriptで作る!チーム開発に適したWebアプリケーションの作り方
OpenAPI generatorを試してみる
俺的【OAS】との向き合い方 (爆速でOpenAPIと友達になろう)
本当に使ってよかったOpenAPI (Swagger) ツール
OpenAPI Generator + TypeScript で始める自動生成の型に守られた豊かなクライアント生活
OpenAPI GeneratorでRESTful APIの定義書から色々自動生成する