OpenAPI 3のドキュメントの一部翻訳

# はじめに
株式会社CAM のAdvent Calendar 10日目です。
昨日は @ohteru さんの「[DIPについて勉強し直してみた](https://qiita.com/ohteru/items/2185984f4019bf77488a)」でした。

僕は最近Open APIやSwaggerに触れるようになったのですが、呼び方が違ったり、色々ツールがあったりでさっぱり理解できませんでした。そこで、公式のページをみていたのですが、公式は英語しかないのでちょっと辛いなと思い、自分が勉強した部分のみ翻訳をしてみました。


# What is OpenAPI?
OpenAPI Specification(この前までのSwagger Specification)は REST APIの記述フォーマットです。
OpenAPI fileはAPIを以下の要素を含ませて定義できます。

- 利用可能なエンドポイント(/users)とその操作(GET /users, POST /users)
- それぞれのオペレーションの入力と出力
- 認証メソッド
- ライセンス、利用規約、問い合わせ先などの情報

API SpecificationはYAMLまたはJSONで記述できます。フォーマットは簡単で、機械にも人間にも読みやすいものになっています。
完全なOpenAPI Specificationは [Github上](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.0.md)で確認できます。

## What is Swagger?
SwaggerとはOASに関連して作られ、設計したり、ビルドしたり、仕様書の作成を手助けしてくれるオープンソースツールの集まりのことです。
主なツールは

- *Swagger Editor* - OASを書くことができるブラウザベースのエディタです。
- *Swagger UI* - OASをインテラクティブなAPI仕様書として表示するツールです。
- *Swagger Codegen* - サーバのスタブやOASのクライアントのsdkを生成するツールです。

## Why Use OpenAPI?
API構造を書き上げることはOpen APIにおけるはじめの一歩です。一度書けば、OASとSwagger toolsが様々な方法でAPI開発を手助けします。

- Swagger Codegenを用いてAPIサーバのstubを生成することができます。サーバーのロジックを追加するだけでstubを動かすことができます。
- Swagger Codegenでクライアントのライブラリを生成することができます。40以上の言語に対応しています。
- Swagger UIを用いることでドキュメントを生成することができ、ブラウザ上でAPIを試すことができます。
- specをAPI関連ツールに繋げることができます。例えば、specを[SoupUI](https://www.soapui.org/)に取り入れることで、APIの自動テストを行うことができます。
- ほかのSwaggerと連携するツールも[open-source](https://swagger.io/open-source-integrations/)と[commercial tools](https://swagger.io/commercial-tools/)でチェックしましょう!

# Basic Structure
OpenAPIはYAMLとJSON形式で記述できます。こちらではYAMLでの例を示しますが、JSONでも同様に動作します。
OpenAPI 3.0のYAMLでの定義はこのようになります。

```.yaml
openapi: 3.0.0
info:
  title: Sample API
  description: Optional multiline or single-line description in [CommonMark](http://commonmark.org/help/) or HTML.
  version: 0.1.9
servers:
  - url: http://api.example.com/v1
    description: Optional server description, e.g. Main (production) server
  - url: http://staging-api.example.com
    description: Optional server description, e.g. Internal staging server for testing
paths:
  /users:
    get:
      summary: Returns a list of users.
      description: Optional extended description in CommonMark or HTML.
      responses:
        '200':    # status code
          description: A JSON array of user names
          content:
            application/json:
              schema: 
                type: array
                items: 
                  type: string
```

すべてのキーワードは `case-sensitive`です。

※ `case-sensitive`とは

> プログラムの大文字と小文字を区別数プログラムの性能のこと。
簡単に説明すると、RUNとrunを別のものとして識別します。
文字の大文字小文字を区別しないプログラミング言語は `case-insensitive`です。

[参考文献](https://www.webopedia.com/TERM/C/case_sensitive.html)

## Metadata
API定義は必ず OpenAPI Specificationのバージョンを含めなければなりません。

```.yaml
openapi: 3.0.0
```

OpenAPIバージョンは、何をどのようにしようとして書くかといったAPI定義の全体構造を決めます。
OpenAPI 3.0は [semantic versioning](http://semver.org/)という三つの数字を用いた表現方法を用います。
利用可能なバージョンは、3.0.0, 3.0.1, 3.0.2です。これらの機能はすべて同じです。

`info`節には、`title`, `descrirption`, `version`といったAPIの情報を含みます。

```.yaml
info:
  title: Sample API
  description: Optional multiline or single-line description in [CommonMark](http://commonmark.org/help/) or HTML.
  version: 0.1.9
```

`title`はAPIの名前、`description`はAPIに関する追加の情報です。これは[multiline](http://stackoverflow.com/a/21699210) [CommonMark](http://commonmark.org/help/)

## Servers
`servers`節にはAPIサーバとbase URLを詳述します。一つまたは複数を定義できます。
例、本番環境と開発環境(sandbox)

```.yaml
servers:
  - url: http://api.example.com/v1
    description: Optional server description, e.g. Main (production) server
  - url: http://staging-api.example.com
    description: Optional server description, e.g. Internal staging server for testing
```

すべてAPIのパスはこのserverのURLに紐付きます。上記の例では、`/users`は選択されているサーバによって
`http://api.example.com/v1/users` または `http://staging-api.example.com/users`
となります。詳しい情報は[こちら](https://swagger.io/docs/specification/api-host-and-base-path/)です。


## Paths
`paths`節ではAPI、HTTPメソッド(オペレーション)のそれぞれのエンドポイントを定義できます。例として、`GET /users`は以下のように表現できます。

```.yaml
paths:
  /users:
    get:
      summary: Returns a list of users.
      description: Optional extended description in CommonMark or HTML
      responses:
        '200':
          description: A JSON array of user names
          content:
            application/json:
              schema: 
                type: array
                items: 
                  type: string
```
オペレーションの定義には、パラメータ、リクエストのbody、レスポンスのステータスコード(200 OK, 404 Not Found)などやレスポンスの内容が含まれます。詳しい情報は、[Paths and Operations](https://swagger.io/docs/specification/paths-and-operations/)をご確認ください。

## Parameters
オペレーションはURLのpathを通して、あるいはクエリ文字列で、あるいはヘッダーやクッキーでパラメータを持ちます。
パラメータはデータ型、フォーマット、それが必須か任意かなどの詳細情報を定義できます。

```.yaml
paths:
  /user/{userId}:
    get:
      summary: Returns a user by ID.
      parameters:
        - name: userId
          in: path
          required: true
          description: Parameter description in CommonMark or HTML.
          schema:
            type : integer
            format: int64
            minimum: 1
      responses: 
        '200':
          description: OK
```
詳しく知りたい方は[Describe Parameters](https://swagger.io/docs/specification/describing-parameters/)をご覧ください。

## RequestBody
もしリクエストがbodyを送信する場合、`requestBody`キーワードでbodyの内容とmediaタイプを設定してください。

```.yaml
paths:
  /users:
    post:
      summary: Creates a user.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                username:
                  type: string
      responses: 
        '201':
          description: Created
```
追加情報は、[Describing Request Bosy](https://swagger.io/docs/specification/describing-request-body/)をご確認ください。

## Responses
それぞれのHTTPメソッドにおいて、200 OKや404 Not Foundのステータスコードとレスポンスのbodyを定義できます。
`schema`はそのまま中に書くか`$ref`で参照するかで定義できます。それぞれの異なるcontentsのタイプに対して例を追加することができます。

```.yaml
paths:
  /user/{userId}:
    get:
      summary: Returns a user by ID.
      parameters:
        - name: userId
          in: path
          required: true
          description: The ID of the user to return.
          schema:
            type: integer
            format: int64
            minimum: 1
      responses:
        '200':
          description: A user object.
          content:
            application/json:
              schema:
                type: object
                properties:
                  id:
                    type: integer
                    format: int64
                    example: 4
                  name:
                    type: string
                    example: Jessica Smith
        '400':
          description: The specified user ID is invalid (not a number).
        '404':
          description: A user with the specified ID was not found.
        default:
          description: Unexpected error
```
レスポンスのHTTPステータスコードは"で"200"のように囲む必要があります(OpenAPI 2.0では囲む必要はありません)。
もっと知りたい方は[こちら](https://swagger.io/docs/specification/describing-responses/)をご覧ください。

## Input and Output Models
`components/schemas`節にはAPI全体でつかわれるデータ構造を定義できます。これらは、パラメータやリクエストのbody、レスポンスのbodyに`schema`が必要な時に`$ref`によって追加する。
例えば、このJSONオブジェクトは

```.json
{
  "id": 4,
  "name": "Arthur Dent"
}
```
はこのように置き換えられます。

```.yaml
components:
  schemas:
    User:
      properties:
        id:
          type: integer
        name:
          type: string
      # Both properties are required
      required:  
        - id
        - name
```

そして、リクエストのbodyとレスポンスのbodyの`schema`はこのように参照されます。

```.yaml
paths:
  /users/{userId}:
    get:
      summary: Returns a user by ID.
      parameters:
        - in: path
          name: userId
          required: true
          type: integer
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/User'
  /users:
    post:
      summary: Creates a new user.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/User'
      responses:
        '201':
          description: Created
```

## Authentication
`securitySchemas`と`security`キーワードは、APIで使われている認証メソッドを表現します。

```.yaml
components:
  securitySchemes:
    BasicAuth:
      type: http
      scheme: basic
security:
  - BasicAuth: []
```

サポートされている認証方法は以下の通りです。
- HTTP認証 Basic, Bearer, etc..
- クッキーやクエリ、ヘッダーへのAPIキー
- OAuth2
- OpenID Connect Discovery

そのほかの情報は[こちら](https://swagger.io/docs/specification/authentication/)を確認ください。

## Full Specification
すべてのOpenAPI 3.0 SpecificationはGithub上で確認できます。
https://github.com/OAI/OpenAPI-Specification/blob/OpenAPI.next/versions/3.0.0.md

# Data Models(Schemas)
## DataTypes
スキーマのデータ型は `type`キーワードによって定義されます。例) `type: string`
OpenAPIは以下の型を定義します。

- string
- number
- integer
- boolean
- array
- object

これらの型は、呼び方は違うかもしれませんが、ほどんどのプログラミング言語に備えてあります。

Mixed Types, Numbers, Minimum and Maximumは省略します。

### Strings
テキストの文字列はこのように定義されます。

```.yaml
type: string
```

文字列の長さは `minLength`と`maxLength`を用いて制限できます。

```.yaml
type: string
minLength: 3
maxLength: 10
```

空の文字列は`minLength`や`pattern`を設定しない限り有効です。

#### String Formats
任意の`format`修飾子は文字列のフォーマットや中身についてのヒントを提供します。

- date - 日付表示 [RFC 3339, section 5.6](https://tools.ietf.org/html/rfc3339#section-5.6) 例) 2017-07-01
- date-time - 時間表示 [RFC 3339, section 5.6](https://tools.ietf.org/html/rfc3339#section-5.6) 例) 2017-07-21T17:32:28Z
- password -  
- byte - base64-encoded 文字列 例) U3dhZ2dlciByb2Nrcw==
- binary - 

しかし、`format`はオープンな値なのでOASに定義されていない値であっても使用することができます。以下が例です。
- email
- uuid
- uri
- hostname
- ipv4
- ipv6
- and others..
　
ツールはフォーマットを入力のバリデーションや、プログラミング言語の特定のタイプに値にするなどに使えます。特定のフォーマットをサポートしていないツールは`format`が設定されていない時と同じように`type`のみを返します。

#### pattern
patternキーワードは文字列の正規表現テンプレートを定義できます。
このテンプレートに一致する値のみが受け付けられます。正規表現シンタックスはJavaScriptで使われているものです。正規表現はcase-sensitive、つまり大文字と小文字に区別があります。例えば、以下のパターンはSSN(123-45-6789)のフォーマットと一致します。

```.yaml
ssn:
  type: string
  pattern: '^\d{3}-\d{2}\d{4}$'
```

正規表現は`^...$`によって囲まれること、そして`^`は文字列の始め、`$`は文字列の終わりを示します。もし `^..$`がない場合、部分一致として動作するので、正規表現として書かれている文字列を含むものが一致します。例えば、`pattern:pet`はpet, petstoreやcarpetを一致とみなします。

Boolean, Null, Arrays, Objects, Files, Any Type, Authentucationは省略します。
# Authentication and Authorization
## Describing Security
セキュリティは `securitySchemes`と`security`キーワードを使って表現します。`securitySchemes`はAPIが提供するすべてのセキュリティスキーマを定義し、 `security`で全てのAPIまたは一部のオペレーションに適用します。

### Step 1. Defining securitySchemes
セキュリティスキーマはすべて `components/securitySchemes`節で定義される必要があります。ここではセキュリティスキーマの`type`について説明します。

- http - Basic、BearerとHTTP認証スキーマ
- apiKey - APIキーとクッキー認証
- uauth2 - OAuth2
- openIdConnect - OpenID  Connect Discovery

これに付随するプロパティはそれぞれの`type`に依存します。以下に示すのはそれぞれのセキュリティスキーマがどのように定義されるかを示します。 ここで、`BasicAuth`, `BearerAuth`などの名前はAPIの機能として追加するときに参照される任意の名前です。

```.yaml
components:
  securitySchemes:
    BasicAuth:
      type: http
      scheme: basic
    BearerAuth:
      type: http
      scheme: bearer
    ApiKeyAuth:
      type: apiKey
      in: header
      name: X-API-Key
    OpenID:
      type: openIdConnect
      openIdConnectUrl: https://example.com/.well-known/openid-configuration
    OAuth2:
      type: oauth2
      flows:
        authorizationCode:
          authorizationUrl: https://example.com/oauth/authorize
          tokenUrl: https://example.com/oauth/token
          scopes:
            read: Grants read access
            write: Grants write access
            admin: Grants access to admin operations
```

### Step 2. Applying  security
`securitySchemes`節でセキュリティスキーマについて定義した後は、それをAPIやその個々の操作に`security`節で追加することで適用することができます。rootレベルで適用する場合、`security`節は設定された認証方法を、オペレーションレベルで上書きされない限りはすべてのAPIとそのオペレーションに適用されます。以下の例は、APIはAPIKeyまたはOauth2を用いて認証されます。 *ApiKeyAuth*と*OAuth2*という名前は上の`securitySchemes`節で定義されたスキーマを参照します。

```.yaml
security:
  - ApiKeyAuth: []
  - OAuth2:
      - read
      - write
# The syntax is:
# - scheme name:
#     - scope 1
#     - scope 2
```

それぞれのスキーマに対して、APIを呼ぶのに必要な認証方法を指定できます。スコープはOAuth2とOpenID Connect Discoveryのために使われます。他のセキュリティスキーマを利用する場合、代わりに空の配列を使います。全体での`security`節はそれぞれのオペレーションに対して違った認証を設定できます(違ったOAuth/OpenIDや、認証を外すことも可能です)。

```.yaml
paths:
  /billing_info:
    get:
      summary: Gets the account billing info
      security:
        - OAuth2: [admin]   # Use OAuth with a different scope
      responses:
        '200':
          description: OK
        '401':
          description: Not authenticated
        '403':
          description: Access token does not have the required scope
  /ping:
    get:
      summary: Checks if the server is running
      security: []   # No security
      responses:
        '200':
          description: Server is up and running
        default:
          description: Something is wrong
```

### Scopes
OAuth 2とOpenID Connectはユーザリソースに対する許可を操作するためにスコープを利用します。 例えば、


## Basic Authorization
## API Keys
APIには認証にAPIキーを用いるものがあります。APIキーとは、クライアントがAPIを呼ぶときに作成したトークンです。キーは以下のようにクエリとして送信できたり、

```.yaml
GET /something?api_key=asbnaoirn024
```

また、ヘッダーとして

```.yaml
GET /something HTTP/1.1
X-API-Key: abcdef12345
```

あるいはクッキーとして送信できます。

```.yaml
GET /something HTTP/1.1
Cookie: X-API-KEY=abcdef12345
```

APIキーは、クライアントとserverしか知らない秘密情報とされています。Basic認証のように、APIキーによる認証はhttps/SSLのようなセキュリティのメカニズムと同じように安全な設計がされています。

### Describing API Keys
OpenAPI 3.0では、以下のように定義されます。

```.yaml
openapi: 3.0.0
...
# 1) Define the key name and location
components:
  securitySchemes:
    ApiKeyAuth:        # arbitrary name for the security scheme
      type: apiKey
      in: header       # can be "header", "query" or "cookie"
      name: X-API-KEY  # name of the header, query parameter or cookie
# 2) Apply the API key globally to all operations
security:
  - ApiKeyAuth: []     # use the same name as under securitySchemes
```

この例では、 リクエストのヘッダーとして送られる`X-API-Key`という名前のAPIキーを定義します。キー名の`ApiKeyAuth`はセキュリティスキーマ用の名前です。`ApiKeyAuth`という名前はAPIにセキュリティスキーマを設定するために、`security`節で再度使われています。注意：`securitySchemes`節だけに名前を設定するだけでは動作しません。APIキーとしての動作をさせるために、`security`でも設定する必要があります。`security`節は全体ではなく、操作(HTTPMethod)ごとに設定することができます。これは特定の操作のみAPIキーが必要な場合に便利です。

```.yaml
paths:
  /something:
    get:
      # Operation-specific security:
      security:
        - ApiKeyAuth: []
      responses:
        '200':
          description: OK (successfully authenticated)
```

一つのAPIで複数の認証をサポートすることもできます。 詳しくは[こちら](https://swagger.io/docs/specification/authentication/#multiple)を確認ください。

### Multiple API Keys
いくつかのAPIでは、API KeyとAppIDのように複数のセキュリティキーを組み合わせて使います。 組み合わせて使われることを明示するには、それらを同じ配列に並べてください。以下が例です。

```.yaml
components:
  securitySchemes:
    apiKey:
      type: apiKey
      in: header
      name: X-API-KEY
    appId:
      type: apiKey
      in: header
      name: X-APP-ID
security:
  - apiKey: []
    appId:  []   # <-- no leading dash (-)
```
次のものとは別ものとして認識されます。

```.yaml
security:
  - apiKey: []
  - appId:  []
```
これはどちらでのキーの認証も可能であることを示しています。詳しくは[こちら](https://swagger.io/docs/specification/authentication/#multiple）をご確認ください。

### 401 Response
401 "Unauthorized" レスポンスをAPIキーが違う、または見つからない場合に返すことができます。このレスポンスは`WWW-Authenticate`ヘッダーを含みます。 他の共通レスポンスと同じように、401レスポンスは全体で利用可能な`components/responses`節で定義可能で、`$ref`を用いて参照できます。

```.yaml
paths:
  /something:
    get:
      ...
      responses:
        ...
        '401':
           $ref: "#/components/responses/UnauthorizedError"
    post:
      ...
      responses:
        ...
        '401':
          $ref: "#/components/responses/UnauthorizedError"
components:
  responses:
    UnauthorizedError:
      description: API key is missing or invalid
      headers:
        WWW_Authenticate:
          schema:
            type: string
```
詳しく知りたい方は、[こちら](https://swagger.io/docs/specification/describing-responses/)をご確認ください。

## Bearer Authentication


### Describing Bearer Authentication
### 401 Response
適切なBearerトークンを含んでいないリクエストに対し、レスポンスとして返すべき401 Unauthorizedを定義できます。これは複数の操作から呼ばれるであろうことから、`components/responses`節に書き、

```.yaml
paths:
  /something:
    get:
      ...
      responses:
        '401':
          $ref: '#/components/responses/UnauthorizedError'
        ...
    post:
      ...
      responses:
        '401':
          $ref: '#/components/responses/UnauthorizedError'
        ...
components:
  responses:
    UnauthorizedError:
      description: Access token is missing or invalid
```

# 余談
## YAMLファイルの拡張子について

[こちら](http://www.tohoho-web.com/ex/draft/extension.htm)の記事より抜粋させていただきますと、
> 3文字拡張子と4文字拡張子
>> 元々は 4文字の拡張子だったものが、Windows 95 の前身である MS-DOS や Windows 3.1 で拡張子を 3文字までしか扱えなかったことから、.html を .htm にしたり、.jpeg を .jpg にしたりなど、拡張子を無理矢理3文字に縮めたものが結構あります。その名残で、現在でも拡張子は 3文字以内にする例が多いようです。

公式？のYAMLに拡張子について質問がされており、理由など詳しい説明はありませんが、`.yaml`の方でできれば用いてくれとの見解がありました。
https://yaml.org/faq.html

# 参考文献
https://swagger.io/docs/specification/about/
https://swagger.io/docs/specification/basic-structure/
https://yaml.org

# いかがだったでしょうか？
学び始めは正直何を勉強すればいいのか分かりませんでしたが、自分が設定するべき項目をしっかりと調べて一つ一つ構築していくことで理解できるようになると思います。まだまだ学ぶべき機能がたくさんあるので、新しい機能を勉強するたびにこちらの記事に追記していこうと思います。
明日は @maruken24 さんの記事です、お楽しみに。