SwaggerでRESTful APIの管理を楽にする

![スクリーンショット 2016-10-03 23.43.04.png](https://qiita-image-store.s3.amazonaws.com/0/28298/a78dd402-35fb-2512-ef55-59301803c7e0.png "スクリーンショット 2016-10-03 23.43.04.png")

# 背景
最近は変化し続ける要件に対応するために、システムも柔軟であることが求められています。
そのため、部分的に変更やスケールの可能なシステムを構築し、API経由で連携するマイクロサービス的アーキテクチャが増えてきています。

そういった設計の中で問題になっていくのが、従来のモノリシックなアプリケーションではIDEやコンパイラなどで行っていた、機能間のインターフェイスをどう管理するかという部分です。


# Swaggerとは?
![スクリーンショット 2016-09-28 21.01.47.png](https://qiita-image-store.s3.amazonaws.com/0/28298/e734d258-dbe7-33f7-5f9c-474939eabc82.png "スクリーンショット 2016-09-28 21.01.47.png")

[Swagger](http://swagger.io/)とはRESTful APIのドキュメントや、サーバ、クライアントコード、エディタ、またそれらを扱うための仕様などを提供するフレームワークです。
公式サイトでは、`The World's Most Popular Framework for APIs`と謳っています。

その理由は、マイクロソフト、Google、IBM、SmartBearなどを大手の企業を含む「[Open API Initiative(RESTful APIのインターフェイスを記述するための標準フォーマットを推進する団体)](https://openapis.org/)」がLinux Foundationの協力のもとで結成され、APIの記述のために採用したのが「[Swagger](http://swagger.io/)」です。
Open API InitiativeはSwaggerをベースに、より充実した標準にしていくと説明しています。

しかし実際にSwaggerについて最初に調べたときに悩むのが、関連用語が多く用途と使い分けが分からないことです。
ここではその中でもよりSwaggerの中心になっている用語を説明し、後半ではそれらを使用しどのように開発を進めていくのかをまとめたいと思います。


# Swagger関連用語

|用語|説明|
|:--|:--|
|Swagger Specification|Swaggerを扱う上で中心となる概念で、Swaggerの仕様に準じた、RESTful APIインターフェイスを記述するためのフォーマット(YAML/JSON)<br>Swagger Editorなどで編集するときには、YAMLを用いる方が扱いやすいが、外部のライブラリやSwagger UIと連携する場合にはJSON形式で使用|
|OpenAPI Specification|Swaggerをベースに作られたRESTful APIインターフェイスを記述するためのフォーマット(JSON)|
|[swagger-core](https://github.com/swagger-api/swagger-core)|Javaのコードから`Swagger Specification`を生成するためのJavaライブラリ|
|[swagger-node](https://github.com/swagger-api/swagger-node)|node.jsのコードから`Swagger Specification`を生成するためのnode.jsライブラリ|
|[swagger-js](https://github.com/swagger-api/swagger-js)|`Swagger Specification`を扱うためのクライアントJavaScriptライブラリ|
|[Swagger Editor](http://editor.swagger.io/)|ブラウザ上で動く`Swagger Specification`のエディタ、リアルタイムで構文チェック、可視化|
|[Swagger Codegen](https://github.com/swagger-api/swagger-codegen)|`Swagger Specification`からクライアントコード生成するコマンドラインツール|
|[Swagger UI](http://swagger.io/swagger-ui/)|`Swagger Specification`から動的にドキュメントを生成するツール|


その他、公式ページの[リンク](http://swagger.io/open-source-integrations/)から関連ツールを確認することができます。


# Swaggerツールの関係性
Swaggerには公式、コミュニティを含め多くのツールやライブラリ、サービスが存在します。
ここではその中で主要な使い方になる2つを紹介します。


### トップダウン形式
1. Swagger Editorで`Swagger Specification`を編集、定義
1. Swagger Codegenで`Swagger Specification`からソースコードを生成

### ボトムアップ形式
1. 既に存在するREST APIのソースコードからSwagger Coreのアノテーションなどを使用し`Swagger Specification`定義
1. 生成された`Swagger Specification`をもとにSwagger UIによって、REST　APIをドキュメント化

![Untitled.png](https://qiita-image-store.s3.amazonaws.com/0/28298/99ae4177-3447-6c1a-992c-bcb68ffb193e.png "Untitled.png")


# Swaggerの使い方
ここからは、トップダウン、ボトムアップそれぞれの具体的な開発の流れをまとめたいと思います。

## トップダウン形式
トップダウンの場合には、まず"Swagger Editor"を使用してYAMLかJSONの`Swagger Specification`を作成していきます。
Webから直接アクセスできる、http://editor.swagger.io/ が楽ですが、業務的に外に出せない情報を扱う場合も多いので、各環境にインストールすることも出来ます。もしもDocker環境があるのであれば環境を汚さず手軽に試せるので https://hub.docker.com/r/swaggerapi/swagger-editor/ がおすすめです。
![スクリーンショット 2016-10-07 0.12.31.png](https://qiita-image-store.s3.amazonaws.com/0/28298/010d82a4-1f2b-b61f-571e-da5d63db328f.png "スクリーンショット 2016-10-07 0.12.31.png")

左側が実際に編集出来るYAMLまたはJSONファイル、右側がその内容をもとに可視化されたUIになっています。


ここからは下記の記述をもとに少しずつ解説していきます。
(`Swagger Specification`の詳細は[こちら](http://swagger.io/specification/)から確認できます。)

```yaml
ml
# Example YAML to get you started quickly.
# Be aware that YAML has indentation based scoping.
# Code completion support is available so start typing for available options.
swagger: '2.0'

# This is your document metadata
info:
  version: "0.0.0"
  title: <enter your title>

# Describe your paths here
paths:
  # This is a path endpoint. Change it.
  /persons:
    # This is a HTTP operation
    get:
      # Describe this verb here. Note: you can use markdown
      description: |
        Gets `Person` objects.
        Optional query param of **size** determines
        size of returned array
      # This is array of GET operation parameters:
      parameters:
        # An example parameter that is in query and is required
        -
          name: size
          in: query
          description: Size of array
          required: true
          type: number
          format: double
      # Expected responses for this operation:
      responses:
        # Response code
        200:
          description: Successful response
          # A schema describing your response object.
          # Use JSON Schema format
          schema:
            title: ArrayOfPersons
            type: array
            items:
              title: Person
              type: object
              properties:
                name:
                  type: string
                single:
                  type: boolean
```



### apiinfo

version情報やタイトルなど

```yaml
swagger: '2.0'

# This is your document metadata
info:
  version: "0.0.0"
  title: <enter your title>
```


### paths

エンドポイントのルートを表します。`paths`以下各エンドポイントを記述します。

```yaml
paths:
  /persons:	
```

また、RESTなどでよく利用するリソースIDなどの変数形式なデータは以下のように記述します。

```yaml
paths:
  /persons/{id}:	

```

### get, post

HTTPメソッドを指定します

```yaml
paths:
  /persons:
  	get:
```


### description

エンドポイントの説明を記述します。

```yaml
get:
  # Describe this verb here. Note: you can use markdown
  description: |
    Gets `Person` objects.
    Optional query param of **size** determines
    size of returned array
```

### parameters

HTTPパラメータを記述します。

```yaml
  parameters:
    -
      name: size
      in: query
      description: Size of array
      required: true
      type: number
      format: double
```



|名前|説明|
|:-----|:---|
|name|パラメータの名前|
|in|queryを指定すると`/persons?id=xx`のようにパラメータで値を送る(postの場合はbody)。pathを指定すると`/persons/{id}`のようにURLでパラメータを送るように設定する|
|description|パラメータの説明|
|required|必須要素か否か|
|type|パラメータの型。string, boolean, numberなど|


### responses

APIのレスポンス情報


```yaml
  responses:
    200:
      description: Successful response
      schema:
        title: ArrayOfPersons
        type: array
        items:
          title: Person
          type: object
          properties:
            name:
              type: string
            single:
              type: boolean
```


|パラメータ名|概要|
|:-----|:---|
|schema|レスポンスの値|
|type|型を指定する。arrayやobjectなど|
|items|配列などの中身|
|properties|プロパティ情報。itemsを入れ子にすることもできる|


### definitions

APIの記述をおこなっていくと、同じ要素が複数箇所で登場する場合がある。
そういった場合には別箇所で要素の定義を行い再利用したほうが便利な場合も多い。
definitionsはこういった、要素を定義し利用することができる。

Locationはオブジェクトの名前

```yaml
definitions:
  Location:
    type: object
    properties:
      id:
        type: string
      name:
        type: string
      latitude:
        type: number
      longitude:
        type: number
```

上記を定義しておくとpropertiesで下記のように`$ref`で呼び出せる

```yaml
  responses:
    200:
      description: OK
      schema:
        type: object
        properties:
          data:
            $ref: '#/definitions/Location'
```

また、下記のように入れ子も可能。

```yaml
definitions:
  Media:
    type: object
    properties:
      id:
        type: integer
      location:
        $ref: '#/definitions/Location'
      comments:
        type: object
        properties:
          data:
            type: array
            items:
              $ref: '#/definitions/Comment'
  Location:
    type: object
    properties:
      id:
        type: string
      name:
        type: string
      latitude:
        type: number
      longitude:
        type: number
  Comment:
    type: object
    properties:
      id:
        type: string
      created_time:
        type: string
      text:
        type: string
```


### セキュリティ

oauthなどのセキュリティ関連も設定も可能。


```yaml
securityDefinitions:
  oauth:
    type: oauth2
    flow: implicit
    authorizationUrl: https://twitter.com/oauth/authorize/?client_id=CLIENT-ID&redirect_uri=REDIRECT-URI&response_type=token
    scopes:
      basic: |
       to read any and all data related to twitter
security:
  - oauth:
    - basic
```

メソッド内でoauthを指定する。

```yaml
paths:
  /statuses/mentions_timeline:
    get:
      description: Returns the 20 most recent mentions for the authenticating user
      security:
       - oauth:
         - basic

```




# `Swagger Specification`からコードを生成
Swagger EditorによってSpecificationは出来上がったので、ここからはソースコードを生成してみます。
といっても、Swagger Editorを使用している場合には非常に簡単で`Generate Server`か`Generate Client`から生成したいコードの種類を選ぶだけです。
![スクリーンショット 2016-10-07 20.26.02.png](https://qiita-image-store.s3.amazonaws.com/0/28298/bde6dc5c-ca60-b65a-9273-8f1ba9338355.png "スクリーンショット 2016-10-07 20.26.02.png")

選択したコードの種類にもよりますが実行環境があれば、多くのものはそのままか、ビルドをすれば使えるので、開発プロジェクトのベースやモックサーバといて活用することが出来ます。

また、Swagger Editorではなくコマンドラインから実行する、[Swagger Codegen](https://github.com/swagger-api/swagger-codegen)を使用してソースを生成することもできます。
コマンドツールをダウンロードして、例えば以下のようなコマンドを実行するとSpringプロジェクトのソースコードが生成されます。

```bash
java -jar swagger-codegen-cli.jar generate swagger.json -l spring
```

Swagger Codegenで生成されるコードはSwagger Editorのコードと同じものになるので、`Swagger Specification`とコードを生成する人が違っていたり、ビルドツールやCIなどのコマンドライン環境から使用したい場合に役立ちます。


## ボトムアップ形式

実際の開発ではトップダウンで生成したソースコードがそのまま扱えない場合も多いと思います。
また、既に開発が始まっているシステムなどはボトムアップ形式でのSwaggerを扱う方が有効な場合も多いと思います。



例ではSpringで作られたアプリケーションから、Swagger APIとUIを提供するSpringfoxを使用します。

説明のために以下のような簡単な機能を持ったAPIを考えてみます。

- 全ユーザ検索と、ユーザIDを指定した検索が可能
- ユーザ登録と削除は管理者機能として提供

コードは以下のような形。

```Java:Sample
@Entity
class User {
	@Id
	@GeneratedValue
	Long id;
	String name;
	int age;

	Long getId() { return id; }
	String getName() { return name; }
	int getAge() { return age; }
	void setId(Long id) { this.id = id; }
	void setName(String name) { this.name = name; }
	void setAge(int age) { this.age = age; }
}

interface UserRepository extends JpaRepository<User, Long> {}

@RestController
@AllArgsConstructor
class SampleController {
    UserRepository repository;   

    @GetMapping("/users/")
    List<User> users() {
        return repository.findAll();
    }

    @GetMapping("/users/{id}")
    User user(@PathVariable Long id) {
        return repository.findOne(id);
    }
    
    @PostMapping("/admin/")
    void create(@RequestBody User user) {
        repository.save(user);
    }
    
    @DeleteMapping("/admin/{id}")
    void delete(@PathVariable Long id) {
        repository.delete(id);
    }
}
```

UserクラスとSpring Data JPAのRepositoryを使用したシンプルなAPIです。


このソースから、まず最小構成でSwagger環境を構築します。

### Dependencyの追加

```groovy:build.gradle
dependencies {
  compile "io.springfox:springfox-swagger2:2.6.0"
}
```
springfox-swagger2はSpringソースからSwagger Coreの機能を利用し、`Swagger Specification`に従ったJSON APIを作成するためのライブラリです。

### Swaggerの有効化
Swaggerのdependencyを追加した後、@Configrationなクラスに@EnableSwagger2を追加して起動します。

```Java
@Configuration
@EnableSwagger2
class Config {}
```

http://localhost:8080/v2/api-docs にアクセスすると、以下のような`Swagger Specification`に従ったJSONが取得できます。

```json
{
  "swagger": "2.0",
  "info": {
    "description": "Api Documentation",
    "version": "1.0",
    "title": "Api Documentation",
    "termsOfService": "urn:tos",
    "contact": {},
    "license": {
      "name": "Apache 2.0",
      "url": "http://www.apache.org/licenses/LICENSE-2.0"
...
```

次にSwagger UIを有効にします。

### Dependencyの追加

```groovy:build.gradle
dependencies {
  compile "io.springfox:springfox-swagger2:2.6.0"
  compile "io.springfox:springfox-swagger-ui:2.6.0" // 追加
}
```
springfox-swagger-uiは`Swagger Specification`形式のAPIを呼び出し、Swagger UIを構築するためのHTMLやJavaScriptを提供します。
Springfoxはこの2つのライブラリにより、`ソースからSwagger Specification` + `Swagger SpecificationからSwagger UI`のボトムアップ形式の開発を容易に可能にします。

起動するとデフォルトでは、[http://localhost:8080/swagger-ui.html](http://localhost:8080/swagger-ui.html)のような{アプリケーションのルートパス}/swagger-ui.htmlがSwagger UIへのパスとなります。
![スクリーンショット 2016-10-01 16.57.41.png](https://qiita-image-store.s3.amazonaws.com/0/28298/301c228f-97aa-51c9-d8e1-8fdf5b798879.png "スクリーンショット 2016-10-01 16.57.41.png")

このようにdependencyの追加と設定クラスを作るだけでソースコードから、閲覧用のSwagger UIを簡単に作成することができます。
また、ソースコードを修正すれば自動的に反映されるので、動作しているアプリケーションからRESTfulなAPIの情報を常時確認することができるようになります。

また、Swagger UIは単純なAPIドキュメントとしてだけでなく、APIを直接呼び出すことのできるインタラクティブな機能を提供します。
必要な`Parameters`などを入力して`Try it out!`ボタンを選択すると実際にAPIを呼び出した結果も確認することが出来ます。
![スクリーンショット 2016-10-07 21.57.04.png](https://qiita-image-store.s3.amazonaws.com/0/28298/6ca92087-e670-fc08-c4f0-abbe66272b89.png "スクリーンショット 2016-10-07 21.57.04.png")




### Swagger UIのカスタマイズ
特に設定を行わない状態でも多くのAPI情報を得ることができますが、もっと細かく情報を追加したくなる場合も多いと思います。
そういった場合には、SwaggerのConfigクラスの修正やソースの中にアノテーションを付加することで追加出来ます。

### Configクラスによるカスタマイズ
Configクラスによるカスタマイズは主にSwagger UI(Swagger Specification API)の全体に関わる設定です。

ここでは例として、先程のConfigクラスに設定を追加し、User用とAdmin用にグループを作成、表示項目を分割してみます。

```java
@Configuration
@EnableSwagger2
class Config {
	@Bean
	public Docket user() {
		return new Docket(DocumentationType.SWAGGER_2)
				.groupName("user")
				.select()
				.apis(RequestHandlerSelectors.withMethodAnnotation(GetMapping.class))
				.paths(PathSelectors.regex("/users.*"))
				.build()
				.apiInfo(apiinfo());
	}

	@Bean
	public Docket admin() {
		return new Docket(DocumentationType.SWAGGER_2)
				.groupName("admin")
				.select()
				.apis(RequestHandlerSelectors.any())
				.paths(PathSelectors.any())
				.build()
				.apiInfo(apiinfo());
	}

	private ApiInfo apiinfo() {
		return new ApiInfoBuilder()
				.title("User API")
				.description("User情報を扱うためのAPIをです。")
				.version("1.0")
				.contact(new Contact("disc99","http://disc99.com", "disc99@mail.com"))
				.build();
	}
}
```

Docketを@Beanによりコンテナに登録することで、Swagger Specificationのメイン情報を設定することが出来ます。

|メソッド|説明|
|:--|:--|
|getName|グループ名を指定することで、複数のDocketを登録することができ、登録するとSwagger UI上部のセレクトボックスからプルダウンでグループを選択が可能|
|select|Swagger Specificationの対象を選択|
|apis|使用するAPIの設定|
|paths|使用するAPIのパスを設定|
|apiInfo|APIの基本情報を設定|

Swagger UIを確認すると、設定項目が反映されています。

![スクリーンショット 2016-10-08 10.26.59.png](https://qiita-image-store.s3.amazonaws.com/0/28298/974933fe-1389-489b-4fb6-6f3675e8ab5b.png "スクリーンショット 2016-10-08 10.26.59.png")

さらに詳しい情報はSpringfoxの[ドキュメント](http://springfox.github.io/springfox/docs/current/)から確認できます。


### アノテーションによるカスタマイズ
アノテーションによるカスタマイズは主に各エントリポイント単位の設定です。
こちらも、先程のAPIに詳細情報を追加します。

```java:
@Entity
class User {
	@Id
	@GeneratedValue
	Long id;
	String name;
	int age;

	@ApiModelProperty(value = "ユーザID", required = true)
	Long getId() { return id; }
	@ApiModelProperty(value = "ユーザ名", required = true)
	String getName() { return name; }
	@ApiModelProperty(value = "ユーザ年齢")
	int getAge() { return age; }
	void setId(Long id) { this.id = id; }
	void setName(String name) { this.name = name; }
	void setAge(int age) { this.age = age; }
}

@RestController
@AllArgsConstructor
class SampleController {
    //...

	@ApiOperation(value = "ユーザ情報取得", notes = "指定されたユーザの情報を取得します。", response = User.class, tags = {"User",})
	@ApiResponses(value = {
			@ApiResponse(code = 200, message = "指定されたユーザ情報", response = User.class)})
	@GetMapping("/users/{id}")
	User user(@ApiParam(value = "ユーザID", required=true) @PathVariable Long id) {
		return repository.findOne(id);
	}

    //...
}
```

今回は以下のアノテーションを使用し、情報を追加しています。
こちらは、Swaggerが提供しているアノテーションで、より詳しい情報は[こちら](https://github.com/swagger-api/swagger-core/wiki/Annotations)から確認することができます。

|アノテーション|説明|
|:--|:--|
|@ApiOperation|APIの操作や、パスなどの情報を設定|
|@ApiResponses, @ApiResponse|APIのレスポンスに関する情報を設定|
|@ApiParam|APIのパラメータに関する情報を設定|
|@ApiModelProperty|APIのモデルに関する情報を設定|


![スクリーンショット 2016-10-08 9.19.29.png](https://qiita-image-store.s3.amazonaws.com/0/28298/9b9858bb-67cd-352f-bea2-efffb96a8e81.png "スクリーンショット 2016-10-08 9.19.29.png")






# Swaggerからドキュメント生成
Swagger UIを用いれば、動的にUIドキュメンテーションを作ることは出来ますが、そのためには動作させるためのサーバが必要になったり、オフライン環境やブラウザを使わなくても確認できるドキュメントが欲しくなる場合もあると思います。
そのような場合に使えるのが、[Swagger2Markup](https://github.com/Swagger2Markup/swagger2markup)です。
このライブラリはSwagger Specificationから、AsciiDocやHTML、PDFなどのドキュメントを作成することができます。
今回は、Springアプリケーション用にSwagger2Markupと統合されたspringfox-staticdocsを使用します。

### Dependencyの追加
先程まで作成していたプロジェクトに以下の依存性を追加します。

```groovy:build.gradle
dependencies {
  compile "io.springfox:springfox-swagger2:2.6.0"
  compile "io.springfox:springfox-swagger-ui:2.6.0"
  testCompile "io.springfox:springfox-staticdocs:2.6.0" // 追加
}
```

### ドキュメント生成コードを記述

ドキュメントを作成するためにはSwagger Specificationを取得するためにテストコードからを記述し作成します。


```java
@WebAppConfiguration
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = Application.class, loader = SpringApplicationContextLoader.class)
public class Swagger2MarkupTest {

    @Autowired
    private WebApplicationContext context;

    private MockMvc mockMvc;

    @Before
    public void setUp() {
        this.mockMvc = MockMvcBuilders.webAppContextSetup(this.context).build();
    }

    @Test
    public void convertSwaggerToAsciiDoc() throws Exception {
        this.mockMvc.perform(get("/v2/api-docs")
                .accept(MediaType.APPLICATION_JSON))
                .andDo(Swagger2MarkupResultHandler.outputDirectory("src/docs/asciidoc/generated").build())
                .andExpect(status().isOk());
    }
}
```

このテストを実行することで、`src/docs/asciidoc/generated`配下に`definitions.adoc`、`overview.adoc`、`paths.adoc`などのasciidocファイルが生成されます。
これらを、[Spring REST Docs](https://github.com/spring-projects/spring-restdocs)と組み合わせて使用することで、実際に動作しているAPIから簡単に今風なドキュメントを作成することが出来ます。
![スクリーンショット 2016-10-07 21.41.37.png](https://qiita-image-store.s3.amazonaws.com/0/28298/9e1254b7-b267-4e86-d534-78f92a7941b2.png "スクリーンショット 2016-10-07 21.41.37.png")


# Swaggerの競合
最後にSwaggerの他にどのような競合があるかも上げておきます。

- [API Blueprint](https://apiblueprint.org/)
MarkdownファイルからAPIドキュメントやサンプルデータになるJSONを生成するための仕様で、[apiary.io](https://apiary.io/)と合わせて使用するこで、REST　APIの一括して管理することができる。

- [RAML](http://raml.org/)
RESTful API Modeling Languageの略で、YAMLをベースにしたREST API定義のための言語。[チャットワークのAPIドキュメント](http://developer.chatwork.com/ja/raml.html)などにも採用されている。

### トレンド
Swaggerは固有名詞ではないのでノイズが入っている可能性もありますが、ここ3年のトレンドを見る限り、Swaggerが優勢なようです。

![Kobito.H7p5Wh.png](https://qiita-image-store.s3.amazonaws.com/0/28298/853d7e33-6e34-8d90-3849-d0f5b65a4f70.png "Kobito.H7p5Wh.png")



# まとめ
Swaggerは `Swagger Specification`を中心にトップダウン、ボトムアップなどSwaggerを使用することで一貫してRESTful APIを扱うことができます。
使い勝手の面ではまだ、競合するツールと迷う部分もありますが、OpenAPI Specificationのベースにもなっているなどの将来性も踏まえると有力な選択肢になると思います。


# 参考
- http://www.publickey1.jp/blog/15/open_api_initiative.html
- https://www.infoq.com/jp/news/2016/02/tony-tam-oai-initiative-swagger
- [swagger introduction](http://qiita.com/tsujimitsu/items/ae886f0e4de86f2b29e4)
- http://www.slideshare.net/takurosasaki/swaggerapi
- http://qiita.com/magaya0403/items/0419d84d8df7784ac465