目次

目次

autorestでAPIクライアントの自動生成

松木佑徒
松木佑徒
最終更新日2017/11/16 投稿日2017/11/16

OpenAPI仕様(旧Swagger)からAPIクライアントのSDKを生成するツールにswagger-codegenがありますが。 同様のツールとしてMicrosoftのオープンソースにautorestがあったので試してみました。

autorestは以下の言語の自動生成に対応しています。 C#, Go, Java, Node.js, TypeScript, Python, Ruby, PHP

swagger-codegenの対応言語一覧はこちら

インストール

autorestコマンドを使えるようにします。 ちなみに、Node.js 7.10以上が必要です。

npm install -g autorest

OpenAPI Specification

今回は以下のようなAPI仕様を定義したとします。

/projects:
  get:
    operationId: listProjects
    summary: プロジェクトの一覧取得
    tags:
      - Project
    parameters:
      - name: pickup
        in: query
        description: ピックアップ
        required: false
        type: string
    responses:
      200:
        description: プロジェクト一覧
        schema:
          type: array
          items:
            $ref: '#/definitions/project'
      400:
        description: 取得NG
        schema:
          $ref: '#/definitions/error'

Pythonクライアントの生成

autorestを呼び出してクライアントを生成します。

--python オプションでPythonクライアントになります。 詳細なオプションはこちらを参考に。

autorest --input-file=swagger.yaml --python --output-folder=autorest_client --namespace=matsu

Pythonクライアントのソース

自動生成されたクライアントのソースコードをautorestとswagger-codegenで比較してみました。

autorest版

def list_projects(self, creator=None, pickup=None, popular=None, custom_headers=None, raw=False, **operation_config):
    """プロジェクトの一覧取得"""
    # Construct URL
    url = '/projects'

    # Construct parameters
    query_parameters = {}
    if pickup is not None:
        query_parameters['pickup'] = self._serialize.query("pickup", pickup, 'str')

    # Construct headers
    header_parameters = {}
    header_parameters['Content-Type'] = 'application/json; charset=utf-8'
    if custom_headers:
        header_parameters.update(custom_headers)

    # Construct and send request
    request = self._client.get(url, query_parameters)
    response = self._client.send(request, header_parameters, **operation_config)

    if response.status_code not in [200, 400]:
        raise HttpOperationError(self._deserialize, response)

    deserialized = None

    if response.status_code == 200:
        deserialized = self._deserialize('[Project]', response)
    if response.status_code == 400:
        deserialized = self._deserialize('Error', response)

    if raw:
        client_raw_response = ClientRawResponse(deserialized, response)
        return client_raw_response

    return deserialized

swagger-codegen版(比較用)

def projects_get_with_http_info(self, **kwargs):
    """プロジェクトの一覧取得"""

    all_params = ['pickup']
    all_params.append('callback')
    all_params.append('_return_http_data_only')
    all_params.append('_preload_content')
    all_params.append('_request_timeout')

    params = locals()
    for key, val in iteritems(params['kwargs']):
        if key not in all_params:
            raise TypeError(
                "Got an unexpected keyword argument '%s'"
                " to method projects_get" % key
            )
        params[key] = val
    del params['kwargs']

    collection_formats = {}

    resource_path = '/projects'.replace('{format}', 'json')
    path_params = {}

    query_params = {}
    if 'pickup' in params:
        query_params['pickup'] = params['pickup']

    header_params = {}

    form_params = []
    local_var_files = {}

    body_params = None
    # HTTP header `Accept`
    header_params['Accept'] = self.api_client.\
        select_header_accept(['application/json'])

    # Authentication setting
    auth_settings = []

    return self.api_client.call_api(resource_path, 'GET',
                                    path_params,
                                    query_params,
                                    header_params,
                                    body=body_params,
                                    post_params=form_params,
                                    files=local_var_files,
                                    response_type='list[Project]',
                                    auth_settings=auth_settings,
                                    callback=params.get('callback'),
                                    _return_http_data_only=params.get('_return_http_data_only'),
                                    _preload_content=params.get('_preload_content', True),
                                    _request_timeout=params.get('_request_timeout'),
                                    collection_formats=collection_formats)

感想

まだautorest版のクライアントは使用していないのですがソースを見た感じの感想です。

  • swagger-codegenのいいところ
    • OperationId を書かなかった場合にPathから自動で関数名が定義されるのでIDの重複を気にしたり余計なルールを用意しなくて済む
    • APIと通信するクライアントを別で生成してAPIの処理に渡せるのでクライアントが使い回せて認証処理を毎回書く必要がない
  • autorestのいいところ
    • OpenAPI仕様で記述したエラーの場合の詰め替えを自動でやってくれるのでSDKの呼び出し元で(余計な)例外処理をしなくて済む
    • 生成されたソースが読みやすい気がする

松木佑徒

目次