今日から始めるswagger入門（最低限書けるようになる）

## swaggerとは
古の時代、API仕様書はwordやexcelで表現され、各所に共有されるというのが一般的でした。
ですが近年、API仕様を表現する際にはswaggerを利用するのが最も効率的で、保守性が高く、世間一般で仕様化され、見やすいというのもあり、一般化されてきたのではないのでしょうか

今回はそんなswaggerの書き方について、まずは書くために覚えておきたいポイントを解説していこうかと思います！

https://swagger.io/

## どう書いてくか
### swagger editorで書く
公式がWeb上に提供しているツールを利用し、すぐにでもswaggerの執筆が可能となっています！
なにをインストールする必要もなく開始1秒で利用できるので、私も重宝してます
なお、ページを開くとサンプルAPI仕様がすでにある状態でのスタートとなり、記法の参考などにもなります

https://editor.swagger.io/

![スクリーンショット 2023-09-02 15.59.43.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/323088/5b1772ab-7955-e4c8-79a6-97cba98ceb3a.png)

### vscodeで書く
必要なプラグインをインストールし、vscode上で執筆するパターンもありです（私は普段こちらの方法です）
おすすめはこちらのプラグインです！

https://marketplace.visualstudio.com/items?itemName=TheHolyCoder.swagger-tools

https://marketplace.visualstudio.com/items?itemName=Arjun.swagger-viewer

win：Ctrl + Shift + P
mac：command + Shift + P
でvscodeのコマンドパレットを開いて、「Preview Swagger」を選択することですぐに内容を確認できるので便利です

![スクリーンショット 2023-09-02 16.12.25.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/323088/97d6e2a8-f3cd-ec4e-0638-d3050507b6e4.png)


![スクリーンショット 2023-09-02 16.03.34.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/323088/d3cd780d-d11b-c4c4-9745-1a56fbff098d.png)


# 書き方
## まず最低限覚えるべきはpaths。pathsの中さえかければなんとかなる
いろんなことを覚えるのは後にして、まずはpaths内をしっかり書けるようになりましょう！
それさえできればAPI仕様を表現できるようになるのと同義になります！

では書いていきますが、以下の順で進めていきましょう
- pathを書く
- リクエストメソッド書く
- API名を書く（省略可能）
- リクエストパラメータ書く（省略可能）
- リクエストレスポンス書く

```yaml
  /tests: # ここがpath（URLの一部になります）
    get:  # ここがリクエストメソッド
      summary: テストAPI # API名
      parameters: # リクエストパラメータ
      - name: test
        in: query
        schema:
          type: string
      responses: # リクエストレスポンス
        200:
          description: success operation
          content:
            application/json:
              schema:
                type: array
                items:
                  type: string
```

このAPIは以下のリクエストメソッド、URLで呼び出し可能であるという表現となります
```
GET http://{domain}/tests?test=xxx
```

## content内のおまじないを覚える
responsesの中身を記述している時、中級者でも書き方忘れる場合が多くあります
ですが早いうちに簡単な傾向さえ覚えてしまえば、今後のswagger開発が捗ること間違いなしです！

### content → Content-Type → schema
swaggerでAPI仕様書を書くタイプの仕事をしているひとの多くは、Content-Typeは「application/json」としてるのではないでしょうか
ですので、以下のように読み替えて覚えましょう
content → application/json → schema

```yaml
  responses:
    200: # ステータスコード
      description: success operation
      # ここから
      content:
        application/json:
          schema:
      # ここまで
            type: object
            properties:
              data:
                type: string
```

:::note info
content → application/json → schema
:::

### type:arrayはitems、type:objectはpropertiesで覚える
json構造を書いていると、 `[]`これと`{}`これを使い分けなければいけませんね
どうしたらどうなる、を覚えていきましょう

`[]`：type:array
`{}`：type:object
と表現すると思った形になると思います

さらに、type:arrayの次にはitemsを、type:objectの次にはpropertiesを続ける必要があるのもルールです！

実際に見てみましょう

#### type: array

```yaml
  responses:
    200:
      description: success operation
      content:
        application/json:
          schema:
            # ここから
            type: array
            items:
            # ここまで
              type: string 
# jsonは以下のようになる
# [
#   "string"
# ]
```

#### type: object

```yaml
  responses:
    200:
      description: success operation
      content:
        application/json:
          schema:
            # ここから
            type: object
            properties:
            # ここまで
              data:
                type: string
# jsonは以下のようになる
# {
#   data: "string"
# }
```

:::note info
`[]`：type:array
`{}`：type:object
type:arrayの次にはitems
type:objectの次にはproperties
:::

## 値の受け渡し方、GETはparameters、POSTはrequestBodyに書く

GETとPOSTは一般的にデータの受け渡し方法に違いがあり、それはswaggerでも表現方法を分ける必要があります
GET：クエリーパラメータ
POST：リクエストボディ

#### クエリーパラメータ
```yaml
  /tests:
    get:
      summary: テストAPI（一覧）
      parameters:
      - name: data
        in: query
        schema:
          type: string
```

#### リクエストボディ
```yaml
  /tests:
    post:
      summary: テスト登録API
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                data:
                  type: string
```


Tips：データ受け渡し方法の違いは、詳しくはこちらの記事がすごい参考になります

https://qiita.com/Sekky0905/items/dff3d0da059d6f5bfabf

#### パスパラメータはGET/POSTに関わらずparametersに
一点注意点があります！
POSTであってもパスパラメータについてはparametersに記述する必要があります
また、その際にはparametersとrequestBodyは共存できます

```yaml
  /tests/{id}/hoge:
    post:
      summary: テストほげ登録API
      # ここから
      parameters:
      - name: id
        in: path # in:pathになっているのにも注目
        required: true # パスパラメータは必須指定が求められます
      # ここまで
        schema:
          type: string
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                data:
                  type: string
```

:::note warn
パスパラメータはGET/POSTに関わらずparametersに書きましょう！
さらに、parametersとrequestBodyは共存できます
:::

## requestBodyとresponsesは基本的に構造は同じ
requestBodyが出てきてお気づきの方もいるかと思いますが、requestBodyとresponsesのステータスコード以下の構造は同じです！

```yaml
  /tests/{id}/hoge:
    post:
      summary: テストほげ登録API
      parameters:
      - name: id
        in: path
        required: true
        schema:
          type: string
      requestBody:
        ## ここから
        content:
          application/json:
            schema:
              type: object
              properties:
                data:
                  type: string
        ## ここまでと
      responses:
        200:
          description: success operation
          ## ここから
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: string
          ## ここまで
```


# 最後にいろんなパターンのswaggerを書いてみたので共有します

```yaml
openapi: 3.0.3
info:
  title: test-api
  version: 0.0.1
tags:
  - name: user
    description: ユーザー情報
paths:
  /users:
    get:
      tags:
        - user
      summary: ユーザー一覧API
      description: |
        ユーザーをデフォルトで全件取得して返却します <br>
        idの昇順。
      responses:
        200:
          description: success operation
          content:
            application/json:
              schema:
                type: array
                items:
                  type: object
                  properties:
                    id:
                      type: string
                    name:
                      type: string
                    address:
                      type: string
                    birthday:
                      type: string
                      format: date
                      example: "1999-01-01"
                      nullable: true
                    age:
                      type: integer
                      nullable: true
                    sex:
                      type: string
                      enum:
                        - MALE
                        - FEMALE
                    memberType:
                      type: string
                      nullable: true
                      enum:
                        - GENERAL
                        - SPECIAL
                        - CHILD
                        - SENIOR
    post:
      tags:
        - user
      summary: ユーザー登録API
      requestBody:
        content:
            application/json:
              schema:
                type: object
                properties:
                  id:
                    type: string
                  name:
                    type: string
                  address:
                    type: string
                  birthday:
                    type: string
                    format: date
                    example: "1909-01-01"
                    nullable: true
                  age:
                    type: integer
                    nullable: true
                  sex:
                    type: string
                    enum:
                      - MALE
                      - FEMALE
                  memberType:
                    type: string
                    nullable: true
                    enum:
                      - GENERAL
                      - SPECIAL
                      - CHILD
                      - SENIOR
      responses:
        200:
          description: success operation
          content:
            application/json:
              schema:
                type: object
                properties:
                  id:
                    type: string
                  name:
                    type: string
                  address:
                    type: string
                  birthday:
                    type: string
                    format: date
                    example: "1909-01-01"
                    nullable: true
                  age:
                    type: integer
                    nullable: true
                  sex:
                    type: string
                    enum:
                      - MALE
                      - FEMALE
                  memberType:
                    type: string
                    nullable: true
                    enum:
                      - GENERAL
                      - SPECIAL
                      - CHILD
                      - SENIOR

  /users/{userId}:
    get:
      tags:
        - user
      summary: ユーザー詳細API
      description: |
        ユーザー詳細を取得して返却します <br>
      parameters:
      - name: userId
        in: path
        description: ユーザーID
        required: true
        schema:
          type: string
          example: 248c8027-b752-db4c-76c1-fb22a05e9591
          nullable: false
      responses:
        200:
          description: success operation
          content:
            application/json:
              schema:
                type: object
                properties:
                  id:
                    type: string
                  name:
                    type: string
                  address:
                    type: string
                  birthday:
                    type: string
                    format: date
                    example: "1909-01-01"
                    nullable: true
                  age:
                    type: integer
                    nullable: true
                  sex:
                    type: string
                    enum:
                      - MALE
                      - FEMALE
                  memberType:
                    type: string
                    nullable: true
                    enum:
                      - GENERAL
                      - SPECIAL
                      - CHILD
                      - SENIOR

  /tests/{id}:
    get:
      summary: テストAPI（詳細）
      parameters:
      - name: id
        in: path
        required: true
        schema:
          type: string
      - name: test
        in: query
        schema:
          type: string
      responses:
        200:
          description: success operation
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: string
                    
  /tests:
    get:
      summary: テストAPI（一覧）
      parameters:
      - name: test
        in: query
        schema:
          type: string
      responses:
        200:
          description: success operation
          content:
            application/json:
              schema:
                type: array
                items:
                  type: string

    post:
      summary: テスト登録API
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                data:
                  type: string
      responses:
        200:
          description: success operation
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: string

  /tests/{id}/hoge:
    post:
      summary: テストほげ登録API
      parameters:
      - name: id
        in: path
        required: true
        schema:
          type: string
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                data:
                  type: string
      responses:
        200:
          description: success operation
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: string

```