Camel OpenAPI Javaでリクエストパラメータの設定

## はじめに

OpenAPIはREST APIの仕様を記述するフォーマットです。Camel 3.1から、OpenAPI 3.0ベースのAPI仕様を自動生成して出力するCamel OpenAPI Javaを提供しています。また、Camelの製品版であるFuseもバージョン7.6からCamel OpenAPI Javaを提供しています。
本記事では、Camel OpenAPI JavaでAPI仕様のリクエストパラメータの生成方法をご紹介します。
※ 本記事の作成に利用したバージョンはFuse 7.9 (Camel 2.23.2.fuse-790054-redhat-00001)です。これ以外のバージョンで操作を再現できることを保証しません。

## Camel OpenAPI Javaの有効化

Camel OpenAPI Javaを有効化するために、Camelプロジェクトのpom.xmlに下記の依存関係を追記する必要があります。

```xml
<dependency>
  <groupId>org.apache.camel</groupId>
  <artifactId>camel-openapi-java</artifactId>
</dependency>
```

## Camel OpenAPI JavaでAPI仕様の生成

下記の通りRest DSLにapiContextPathと必要なapiPropertyを記入します。それぞれ定義の説明は[Camelの公式マニュアル](https://camel.apache.org/components/3.7.x/others/openapi-java.html)で参照できます。

```xml
<restConfiguration apiContextPath="/api-doc" bindingMode="json" component="jetty" contextPath="/" host="0.0.0.0" port="8080">
  <apiProperty key="api.version" value="0.0.0"/>
  <apiProperty key="api.title" value="API Spec Sample"/>
  <apiProperty key="api.description" value="The sample of API spec."/>
</restConfiguration>
<rest id="_rest1">
  <get id="_get1" uri="/items">
    <responseMessage code="200" message="OK"/>
    <to uri="direct:listener"/>
  </get>
</rest>
```

ブラウザでapiContextPath(http\://localhost:8080/api-doc)にアクセスしてJSON型のAPI仕様が生成されたことを確認できます。

```json
{
  "openapi" : "3.0.2",
  "info" : {
    "title" : "API Spec Sample",
    "version" : "0.0.0",
    "description" : "The sample of API spec."
  },
  "servers" : [ {
    "url" : ""
  } ],
  "paths" : {
    "/items" : {
      "get" : {
        "responses" : {
          "200" : {
            "description" : "OK"
          }
        },
        "operationId" : "_rest1",
        "x-camelContextId" : "_context1",
        "x-routeId" : "_get1"
      }
    }
  }
}
```

## API仕様のリクエストパラメータの種類

OpenAPIでサポートするAPI仕様のリクエストパラメータの種類を下記の表に示します。それぞれパラメータの詳細は[OpenAPIの公式マニュアル](https://swagger.io/specification/#parameter-object)で参照できます。

| # | パラメータ | 説明 |
| :---: | :--- | :--- |
| 1 | query | URL末尾に付けるパラメータ。例えば、/items?id=###の場合、idはqueryパラメータとなります。 |
| 2 | header | リクエストヘッダに含めるパラメータ。例えば、 itemId: ###の場合、itemIdはheaderパラメータとなります。 |
| 3 | path | URLの一部とするパラメータ。例えば、/items/{itemId}の場合、itemIdはpathパラメータとなります。 |
| 4 | formData | コンテンツタイプとしてapplication/x-www-form-urlencodedもしくはmultipart/form-dataまたはその両方を利用時に、ペイロードを記述するパラメータ。<br>・application/x-www-form-urlencodedの場合のformDataパラメータは、queryパラメータの書式と似ているペイロードです。例えば、foo=1&bar=swaggerの場合、fooとbarはformDataパラメータとなります。<br>・multipart/form-dataの場合のformDataパラメータは、1つの内部ヘッダーに含めます。例えば、ヘッダーがContent-Disposition: form-data; name="submit-name"の場合、submit-nameはformDataパラメータとなります。 |
| 5 | body | JSON型のリクエストボディに含めるパラメータ。例えば"itemId": "###"の場合、itemIdはbodyパラメータとなります。 |

## API仕様のリクエストパラメータの生成方法

### queryパラメータ

queryパラメータ仕様の生成方法を説明します。Rest DSLに下記の設定を記入します。

```xml
<rest id="_rest1">
  <get id="_get1" uri="/items">
    <param dataType="string" description="Query Parameter Example" name="itemId" type="query"/>
    <responseMessage code="200" message="OK"/>
    <to uri="direct:listener"/>
  </get>
</rest>
```

apiContextPathでqueryパラメータの仕様が生成されたことを確認します。

```json
{
...
  "paths" : {
    "/items" : {
      "get" : {
        "parameters" : [ {
          "name" : "itemId",
          "description" : "Query Parameter Example",
          "schema" : {
            "type" : "string"
          },
          "in" : "query",
          "required" : true
        } ],
... 
}
```

### headerパラメータ

headerパラメータ仕様の生成方法を説明します。Rest DSLに下記の設定を記入します。

```xml
<rest id="_rest1">
  <get id="_get1" uri="/items">
    <param dataType="string" description="Header Parameter Example" name="itemId" type="header"/>
    <responseMessage code="200" message="OK"/>
    <to uri="direct:listener"/>
  </get>
</rest>
```

apiContextPathでheaderパラメータの仕様が生成されたことを確認します。

```json
{
...
  "paths" : {
    "/items" : {
      "get" : {
        "parameters" : [ {
          "name" : "itemId",
          "description" : "Header Parameter Example",
          "schema" : {
            "type" : "string"
          },
          "in" : "header",
          "required" : true
        } ],
... 
}
```

### pathパラメータ

pathパラメータ仕様の生成方法を説明します。Rest DSLに下記の設定を記入します。

```xml
<rest id="_rest1">
  <get id="_get1" uri="/items">
    <param dataType="string" description="Path Parameter Example" name="itemId" type="path"/>
    <responseMessage code="200" message="OK"/>
    <to uri="direct:listener"/>
  </get>
</rest>
```

apiContextPathでpathパラメータの仕様が生成されたことを確認します。

```json
{
...
  "paths" : {
    "/items" : {
      "get" : {
        "parameters" : [ {
          "name" : "itemId",
          "description" : "Path Parameter Example",
          "schema" : {
            "type" : "string"
          },
          "in" : "path",
          "required" : true
        } ],
... 
}
```

Camel OpenAPI Javaでは、pathパラメータをパスに指定したら(波括弧で囲まれる)、自動的に認識されるという便利な機能を提供しています。下記の通りRest DSLでpathパラメータitemIdをパスに設定します。

```xml
<rest id="_rest1">
  <get id="_get1" uri="/items/{itemId}">
    <responseMessage code="200" message="OK"/>
    <to uri="direct:listener"/>
  </get>
</rest>
```

apiContextPathでitemIdがpathパラメータとして認識されたことを確認します。

```json
{
...
  "paths" : {
    "/items/{itemId}" : {
      "get" : {
        "parameters" : [ {
          "name" : "itemId",
          "schema" : {
            "type" : "string"
          },
          "in" : "path",
          "required" : true
        } ],
...
}
```

### formDataパラメータ

formDataパラメータ仕様の生成方法を説明します。Rest DSLに下記の設定を記入します。

```xml
<rest id="_rest1">
  <get id="_get1" uri="/items">
    <param dataType="string" description="FormData Parameter Example" name="itemId" type="formData"/>
    <responseMessage code="200" message="OK"/>
    <to uri="direct:listener"/>
  </get>
</rest>
```

apiContextPathでformDataパラメータの仕様が生成されたことを確認します。

```json
{
...
  "paths" : {
    "/items" : {
      "get" : {
        "parameters" : [ {
          "name" : "itemId",
          "description" : "FormData Parameter Example",
          "schema" : {
            "type" : "string"
          },
          "in" : "formData",
          "required" : true
        } ],
        "responses" : {
          "200" : {
            "description" : "OK"
          }
        },
... 
}
```

### bodyパラメータ

bodyパラメータ仕様の生成方法を説明します。Rest DSLに下記の設定を記入します。注意すべきのは、`rest`要素で`consumes`属性を`application/json`に設定する必要があることと、`post`要素で`type`属性をリクエストボディのスキーマを記述するJavaクラスに指定する必要があることです。

```xml
<rest consumes="application/json" id="_rest1">
  <post id="_post1" type="com.example.Customer" uri="/items">
    <param description="Body Parameter Example" name="body" type="body"/>
    <responseMessage code="200" message="OK"/>
    <to uri="direct:listener"/>
  </post>
</rest>
```

`type`で指定したcom.example.Customerの中身を下記に示します。

```java
package com.example

public class Customer {

    private Long id;
    private String firstName;
    private String lastName;

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getFirstName() {
        return firstName;
    }

    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }

    public String getLastName() {
        return lastName;
    }

    public void setLastName(String lastName) {
        this.lastName = lastName;
    }

    @Override
    public String toString() {
        return "Customer{" + "id=" + id + ", firstName='" + firstName + '\'' + ", lastName='" + lastName + '\'' + '}';
    }
}
```

apiContextPathでbodyパラメータの仕様が生成されたことを確認します。

```json
...
  "paths" : {
    "/items" : {
      "post" : {
        "requestBody" : {
          "description" : "Body Parameter Example",
          "content" : {
            "application/json" : {
              "schema" : {
                "$ref" : "#/components/schemas/Customer"
              }
            }
          },
          "required" : true
        },
  ...
  "components" : {
    "schemas" : {
      "Customer" : {
        "type" : "Customer",
        "x-className" : {
          "format" : "org.wildfly.camel.examples.rest.model.Customer",
          "type" : "string"
        }
      }
    }
  }
...
}
```

上記の通り、bodyパラメータは1つの文字列として認識されたようです。比較として、OpenAPI 2.0ベースのAPI仕様を生成するCamel Swagger Javaで同じ設定で生成するbodyパラメータの仕様を以下に示します。

```json
...
  "paths" : {
    "/items" : {
      "post" : {
        "operationId" : "_rest1",
        "consumes" : [ "application/json" ],
        "produces" : [ "application/json" ],
        "parameters" : [ {
          "in" : "body",
          "name" : "body",
          "description" : "Body Parameter Example",
          "required" : true,
          "schema" : {
            "$ref" : "#/definitions/Customer"
          }
        } ],
  ...
  "definitions" : {
    "Customer" : {
      "type" : "object",
      "properties" : {
        "id" : {
          "type" : "integer",
          "format" : "int64"
        },
        "firstName" : {
          "type" : "string"
        },
        "lastName" : {
          "type" : "string"
        }
      }
    }
  }
...
```

上記の通り、Camel Swagger Javaを利用する場合、bodyパラメータの中身も解析されます。このような機能はCamel OpenAPI Javaではまだ実装されていないようです。

## おわりに

本記事では、Camel OpenAPI JavaでAPI仕様のリクエストパラメータの生成方法をご紹介しました。bodyパラメータの中身を解析する機能はまだ実装されていないのは少し残念ですが、簡単な設定でAPI仕様を自動生成できるのは非常に便利であると思います。