開発効率を上げる!Swaggerの記法まとめ

f:id:vasilyjp:20170706190042p:plainこんにちは! バックエンドエンジニアのりほやんです。 以前、テックブログでAPIモックと仕様書を作成することができるSwaggerについてご紹介しました。 Swaggerそのものについて知りたい場合やSwaggerを実際に導入したい場合は、こちらの記事がとても参考になります。

tech.vasily.jp

本記事では、SwaggerのAPI定義を行うSwagger YAMLの記法についてまとめてみました。 使い初めはとっつきにくいSwaggerですが、この記事がSwaggerを使う方の参考になれば幸いです。

目次

Swagger Editorの紹介

Swagger YAMLを書く際には、Swagger Editorがとても便利です。 画面左側がエディター、右側がSwagger UIとなっておりリアルタイムで記法のチェックや定義書を確認できます。 Swaggerを書くエディタはいろいろありますが、気軽に記法を試す際にはSwagger Editorがとても便利です。 ぜひこれから紹介する記法を試す際にも、ぜひ使ってみてください。

初級編

基本の記述

初めにSwagger YAMLを記述するにあたり必須であるswagger, info, pathsについて説明します。 上記の基本的な構成で記述したシンプルなSwagger YAMLがこちらです。

swagger: "2.0"
info:
  description: "これはペットストアに関するAPIです。"
  version: "1.0.0"
  title: "Petstore API"
  termsOfService: "http://swagger.io/terms/"
  contact:
    email: "apiteam@swagger.io"
  license:
    name: "Apache 2.0"
    url: "http://www.apache.org/licenses/LICENSE-2.0.html"
paths:
  /pet/{petId}:
    get:
      summary: "ペット情報API"
      description: "指定されたpetIdの情報を返します"
      parameters:
      - name: "petId"
        in: "path"
        description: "取得したいペットのID"
        required: true
        type: "integer"
        format: "int64"
      responses:
        200:
          description: "成功時のレスポンス"
          schema:
            type: "object"
            properties:
              id:
                type: "integer"
                format: "int64"
              name:
                type: "string"
                example: "doggie"

以降、このサンプルを基に記法を説明します。 実際に上記のSwagger YAMLをSwagger Editorに入力すると、画面右側にAPI定義書が下記のように作成されます。

f:id:vasilyjp:20170706160736p:plain

それでは、 swagger, info, pathsそれぞれのオブジェクトの書き方について説明します。

f:id:vasilyjp:20170706160747p:plain

swagger

swaggerには、Swaggerのバージョンを記述します。 変更する理由がない限りはここの値は 2.0にしておきます。

info

タイトル・説明・バージョンなど、APIについての情報を記載します。 infoには、以下の情報を記述できます。

フィールド名 説明 必須
version string APIのバージョン 必須
title string ドキュメントのタイトル。一番上に表示される。 必須
description string ドキュメントについての説明
termsOfService string 利用規約
contact contact object APIについての問い合わせ先
license license object APIのライセンス

paths

APIのエントリポイントを記述します。 サンプルでは下記の部分にあたります。

f:id:vasilyjp:20170706160805p:plain

ここで定義する情報をもとにエントリポイントが作成されるため、pathsはとても重要なパートとなります。 pathsには、下記のような階層形式で情報を記載します。

  • パスのURL(/pet/{PetId})
    • HTTPメソッド(get, postなど)
      • エントリポイントのリクエストとレスポンスに関する記述

f:id:vasilyjp:20170706160834p:plain

パスのURL

実際に定義したいエントリポイントのパスを記述します。 サンプルでいうところの /pet/{petId}です。

HTTPメソッド(get, post, put, delete等)

パスの下には、パスのHTTPメソッドを記述します。 下記のように複数記述することもできます。

  /pet/{petId}:
    get:
      summary: "ペット情報API"
      description: "指定されたpetIdの情報を返します"
      parameters: 省略
      responses: 省略 
    delete:
      summary: "ペット情報API"
      description: "指定されたpetIdを削除します"
      parameters: 省略
      responses: 省略

エントリポイントのリクエストとレスポンスに関する記述

HTTPメソッドの下層には、エントリポイントがどのようなリクエストを受け取り、どのようなレスポンスを返すかを記述します。 サンプルでは、この部分にあたります。

f:id:vasilyjp:20170706160846p:plain

設定できるフィールドは以下になります。

フィールド名 説明 必須
responses response object 返ってくるレスポンス 必須
parameters parameter object リクエストのパラメーター
tags array swaggerオブジェクトで定義するどのtagに紐付けたいかを記述
summary string エントリポイントの概要(120文字以内)
description string エントリポイントの説明
consumes/produces array MIME Type
schemes array APIの通信プロトコル。必ずhttp, https, ws, wssの4種類のどれかを記述する。
security security requirement object 適用するセキュリティ
externalDocs external docs document 外部リンク
deprecated boolean Deprecatedかどうかをtrueかfalseで記述。デフォルトはfalse。

もっとも重要なparametersとresponsesについて補足説明します。

parameters

リクエストの際に渡すパラメーターを記述します。 サンプルでは下記の部分にあたります。

f:id:vasilyjp:20170706160901p:plain

記述するフィールドは以下です。

フィールド名 説明 必須
name string パラメーター名 必須
in string パラメータの場所。query, header, path, formDataの4種類のどれかを記述してください 必須
description string パラメータの説明
required boolean 必須パラメーターかどうかをtrueかfalseで記述
schema schema object bodyのパラメーターをスキーマオブジェクトとして記述。スキーマオブジェクトについては後述。inがbodyである場合に使用。 inがbodyである場合、必須
type string パラメーターのタイプ。
必ずstring, number, integer, boolean, array, fileの中から選ぶ。inがbody以外である場合に使用。
inがbody以外である場合、必須
format string パラメーターの型。こちらから選ぶ。inがbody以外である場合に使用。

typeとformatの指定は、こちらが参考になります。

パラメーターが記述されると定義書ではこのように表示されます。

f:id:vasilyjp:20170706160914p:plain

responses

返ってくるレスポンスを記述します。 サンプルでは下記の部分にあたります。

f:id:vasilyjp:20170706160925p:plain

返したいHTTPステータスコードごとに、定義を行います。 定義できる設定は下記です。

フィールド名 説明 必須
description string レスポンスの説明 必須
schema schema object レスポンスのbody。スキーマオブジェクトで記述する。スキーマオブジェクトについては後述。
headers headers object レスポンスヘッダーを記述
example example object レスポンス例。レスポンスの値を自分で定義したいときに用いる。

レスポンスを設定すると定義書が下記のように生成されます。

f:id:vasilyjp:20170706160940p:plain

スキーマオブジェクトについて

parameters, responsesを記述する際に、schemaを記述することができます。 このschemaにはスキーマオブジェクトを記述します。 スキーマオブジェクトは、bodyに用いるデータのタイプを定義することができるオブジェクトです。 主に配列かJSONオブジェクトを表現するときに使います。

JSONオブジェクト

schema:
  type: object

と指定すると、JSONオブジェクトを返すことができます。 例えば、APIのレスポンスを下記のように返したいとします。

{
  "id": 1,
  "name": "doggie"
}

この場合はschemaをこのように書きます。

schema:
  type: object
  properties:
    id:
      type: "integer"
      format: "int64"
      example: 1
    name:
      type: "string"
      example: "doggie"

type: objectを指定した場合は、propertiesを設定します。 propertiesでは、カラムの情報を記述します。 propertiesには基本的に下記3つが記述されていれば動作します。

フィールド名 説明
type string パラメーターのタイプ。必ずstring, number, integer, boolean, array, fileの中から選ぶ。
format string パラメーターの型。
example typeで選んだ型 レスポンスで返したい文言

typeとformatの指定は、こちらが参考になります。

配列

schema:
  type: array

と指定すると、配列を定義することができます。 例えば、APIのレスポンスを下記のように返したいとします。

[
  {
    "id": 1,
    "name": "doggie"
  }
]

この場合はschemaをこのように書きます。

schema:
  type: array
  items:
    type: "object"
    properties:
      id:
        type: "integer"
        format: "int64"
        example: 1
      name:
        type: "string"
        example: "doggie"

type: arrayを指定した場合は、itemsを設定します。 itemsには、配列の中のオブジェクトを記述します。 配列の中に、JSONを定義したい場合は、type:objectを指定します。

schema:
  type: array
  items:
    type: "object"
    properties:
      id:
        type: "integer"
        format: "int64"
        example: 1
      name:
        type: "string"
        example: "doggie"

また、配列の中に文字列を定義したい場合は、 type: stringを記述します。

schema:
  type: array
  items:
    type: "string"

中級編

Swaggerを構成するオブジェクト

Swaggerは初級編で紹介したswagger, info, pathsも合わせ計15種類のオブジェクトから成り立っています。 多く感じられますが、すべてが必須というわけでなく、必須であるswagger, info, pathsが記載されていれば動きます。 必須以外のものは定義書に記載したいものがあれば記述します。

フィールド名 説明 必須
swagger string swaggerのバージョン。特に指定がなければ、デフォルトの2.0のままで大丈夫です。 必須
info info object タイトル・説明・バージョンなど、APIについての情報を記載します。 必須
paths paths object 提供するAPIのパスを書いていきます。Swagger定義の要です。 必須
host string API通信を行うサーバーのホスト。無記載であればドキュメントが動いているサーバーのホストとなります。
basePath string ホストに続くパス。スラッシュ(/)から始まる必要があります。無記載の場合、ホストの直下になります。
hostをexample.com
basePathを/v2とした場合、APIのパスはhttp://example.com/v2/〜となります。
schemes array APIの通信プロトコル。必ずhttp, https, ws, wssの4種類のどれかを記載してください。無記載の場合、Swaggerの定義書がアクセスしているスキームになります。
produces array APIが提供できるMIME Typeの指定。選択肢はこちら
consumes array APIが使用するMIME Typeの指定。選択肢はこちら
definitions definitions object レスポンスやパラメータに使用するデータ定義を記載します。
parameters parameters definitions object パラメーターを定義します。pathsの下に直接パラメーターを書くこともできますが、複数回同じパラメーターを使う場合に便利です。
responses responses definitions object レスポンスを定義します。pathsの下に直接レスポンスを書くこともできますが、複数回同じレスポンスを使う場合に便利です。
securityDefinitions security definitions object セキュリティに関する定義を行えます。Oath認証についてもこちらで定義します。
security security requirement object securityDefinitionsにて定義したセキュリティの中で何を適用するかを指定します。
tags [tag object] タグの名前と説明を定義します。定義したタグをpathに紐付けることで、タグごとにpathがまとまりドキュメントが見やすくなります。
externalDocs external documentation object 外部リンクを定義します。ドキュメントに貼りたいリンクがある場合、記載することでリンクが作成されます。

それぞれのオブジェクトの記述は、Swagger Editorにデフォルトで入っているPet store APIがわかりやすく参考になります。

definitionsを使う

同じスキーマオブジェクトを複数回使用したい場合、definitionsを使用しテンプレートとして定義することができます。

f:id:vasilyjp:20170706161012p:plain

definitionsを使う際のポイントは、下記のようになります。

  • テンプレート化したいスキーマオブジェクトを、definitionsに定義をする
  • 呼び出したい箇所に、$refを使用して、definitionsのオブジェクトを呼び出す

サンプルをdefinitionsを用いて書き換えると以下のようになります。

paths:
  /pet/{petId}:
    get:
    省略
      responses:
        200:
          description: "成功時のレスポンス"
          schema:
            $ref: "#/definitions/Pet" # definitionsで定義されたスキーマオブジェクトを呼び出す
definitions:
  Pet: # テンプレート名
    type: "object"
    properties:
      id:
        type: "integer"
        format: "int64"
      name:
        type: "string"
        example: "doggie"

definitionsは本当に便利です。 definitionsにレスポンスのスキーマを全て定義しpathsではそれらを呼び出すだけというような記述にすると、Swagger YAMLが見やすくなるのでオススメです。

definitionsを複数呼び出す

definitionsにて定義したスキーマオブジェクトを複数呼び出すことも可能です。 下記のように、Storeの情報をdefinitionsで定義して呼び出してみます。

paths:
  /pet/{petId}:
    get:
    省略
      responses:
        200:
          description: "成功時のレスポンス"
          schema:
            type: "object"
            properties:
              pet:
                $ref: "#/definitions/Pet" 
              store:
                $ref: "#/definitions/Store"
definitions:
  Pet: 
    type: "object"
    properties:
      id:
        type: "integer"
        format: "int64"
      name:
        type: "string"
        example: "doggie"
  Store:
    type: "object"
    properties:
      id:
        type: "integer"
        format: "int64"
        example: 1
      store_name:
        type: "string"
        example: "ABC PET STORE"

レスポンスはこのようになります。

{
  "pet": {
    "id": 0,
    "name": "doggie"
  },
  "store": {
    "id": 1,
    "store_name": "ABC PET STORE"
  }
}
schema:
  type: "object"

上記のように記述し、JSONオブジェクトのそれぞれのキーにdefinitionsで定義したスキーマオブジェクトを呼び出します。

上級編

definitionsを入れ子にする

中級編では、レスポンスにdefinitionsで定義したスキーマオブジェクトを呼び出しました。 definitionsはスキーマオブジェクトを定義し、呼び出すことができるのでschemaが使えるところではどこでも呼び出すことができます。

例えば、definitionsの中でスキーマオブジェクトを呼び出すことも可能です。

paths:
  /pet/{petId}:
    get:
    省略
      responses:
        200:
          description: "成功時のレスポンス"
          schema:
            $ref: "#/definitions/Pet" 
definitions:
  Pet: 
    type: "object"
    properties:
      id:
        type: "integer"
        format: "int64"
      name:
        type: "string"
        example: "doggie"
      stores:
        type: "array"
        items:
          $ref: "#/definitions/Store" # Storeを呼び出す
  Store:
    type: "object"
    properties:
      id:
        type: "integer"
        format: "int64"
        example: 1
      store_name:
        type: "string"
        example: "ABC PET STORE"

上記のようにレスポンスを定義した場合、レスポンスはこのように生成されます。

{
  "id": 0,
  "name": "doggie",
  "stores": [
    {
      "id": 1,
      "store_name": "ABC PET STORE"
    }
  ]
}

storesの配列の中で、itemsの1つとしてStoreオブジェクトを呼び出しています。

Swagger YAMLを書く上で気をつけたい点

ここからは、実際に私がSwagger YAMLを書く上でうまくいかなかったりつまづいた点を共有の意味を込めてご紹介します。

レスポンスの配列に複数データを入れたい

通常レスポンスに配列を定義する際は、このように記述します。

schema:
  type: array
  items:
    type: "object"
    properties:
      id:
        type: "integer"
        format: "int64"
        example: 1
      name:
        type: "string"
        example: "doggie"

この記述で返ってくるレスポンスは[ { id: 1, name: "doggie" } ]と要素が1つしか返ってきません。 2つ以上の配列要素を追加したい場合は、オブジェクト自体のexampleを記述します。

paths:
  /pet/{petId}:
    get:
    省略
      responses:
        200:
          description: "成功時のレスポンス"
          schema:
            type: "object"
            properties:
              pet:
                $ref: "#/definitions/Pet" 

definitions:
  Pet: 
    type: "array"
    items:
      example:
        - id: 1
          name: "doggie"
        - id: 2
          name: "pochi"

formatを指定しても、デフォルトで値が入らない

Swaggerのドキュメントには、スキーマオブジェクトのformatにemailやuuidを指定するとexampleを設定しなくても値が入るという記述があります。 実際、Swagger Editorでは下記のようにデフォルトで値が入ります。

f:id:vasilyjp:20170706161037p:plain

しかし、Swagger Codegenを使ってモックアプリケーションを生成する場合には、formatを指定してもデフォルトで値が入りません。 formatのデフォルト値を使用する際は、ご自分の環境でデフォルト値が入るかどうかを確認してから使う方が良いと思います。

Amazon API Gatewayではexampleが使えない

Swaggerを用いてAPIを生成するサービスの1つに、Amazon API Gatewayがあります。 API Gatewayは、Swagger YAMLをインポートすることで簡単にAPIを作成することができます。 API Gatewayを用いてAPIを作成する方法については、下記の2つが参考になるのでぜひ読んでみてください。

API GatewayにSwagger YAMLをインポートしてモックアプリケーションを作成する場合は、exampleが使えません。 exampleが記述されているSwagger YAMLをAPI GatewayでロードするとInvalid model schema specifiedというエラーが返ってきます。 API Gatewayでレスポンス例を記述したい時は、下記のように総合レスポンスの設定時に記述しましょう。

f:id:vasilyjp:20170706161053p:plain

まとめ

以上、基本的なSwagger YAMLの書き方についてご紹介しました! Swaggerは高機能であるゆえに、最初はとてもとっつきにくく感じてしまいます。 しかし一度覚えてしまえば、Swaggerは開発効率を上げることができるとても便利なフレームワークです。 この記事では紹介しきれなかった機能も多くあるので、ぜひこちらのドキュメントを参考にしてみてください。

VASILYでは、一緒にバックエンド開発をする仲間を大募集しています♪ ご興味のある方は、こちらからご応募ください。

www.wantedly.com

参考