OpenAPI GeneratorでJavaのAPIクライアントを自動生成する

こんにちは、エキサイト株式会社の平石です。

今回は、OpenAPI Generatorを利用してJavaAPIクライアントを自動生成する方法をご紹介します。

はじめに

アプリケーションを開発していると、自社(自身)で開発したAPIを利用することがあります。

例えば、自社で利用している複数のサービスに共通のAPIがあり、実際のサービスや機能を実装するための処理でそのAPIを呼び出す場合が考えられます。

このような時、「HTTPクライアントを用意」、「エンドポイントと必要なパラメータを確認」、「パラメータ名を間違えないようにセット」などの面倒なことをAPIを呼び出す度に行わなければなりません。
また、前述のような共通のAPIを呼び出す場合には、同じような処理が複数のサービスや機能のソースコードに出現してしまいます。

そのため、APIクライアントのコードを自動生成できると開発の効率が良くなることが期待できます。

OpenAPI Generatorとは

OpenAPIAPIの仕様を記述するためのフォーマットのようなものです。
これに従って「必要なパラメータ」や「レスポンスの形式」「認証の方法」のようなAPIに関する情報を、YAMLJSON形式で記述することでドキュメントを作成することができます。

OpenAPI Generatorは、OpenAPIの仕様に則って作成されたドキュメントから、APIクライアントコードやAPIを実装するための雛形となるコードを自動生成してくれます。

様々な言語に対応していますが、今回はJavaAPIクライアントを自動生成していきます。

OpenAPIの仕様に則って作成されたドキュメントから自動生成するため、呼び出し先のAPIはどの言語で記述されていても問題ありません。

準備

環境

今回は以下のような環境を利用します。

使用するAPIドキュメント

今回は以下のようなYAML形式で記述されたAPIドキュメントからAPIクライアントを生成します。

openapi: 3.0.1
info:
  title: OpenAPI definition
  version: v0
servers:
- url: http://localhost:8190
  description: Generated server url
paths:
  /user:
    get:
      tags:
      - user
      summary: ユーザー取得
      operationId: getUser
      parameters:
      - name: userId
        in: query
        description: ユーザーID
        required: true
        schema:
          type: string
          description: ユーザーID
          example: 11111111
        example: 11111111
      responses:
        "200":
          description: 正常に処理が終了した場合
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/UserResponseDto'
components:
  schemas:
    UserResponseDto:
      title: ユーザーのレスポンス
      required:
      - email
      - userId
      - userName
      type: object
      properties:
        userId:
          title: ユーザーID
          type: string
          example: "11111111"
        userName:
          title: ユーザー名
          type: string
          example: 白金 高輪
        email:
          title: メールアドレス
          type: string
          example: takanawa.shirokane@example.com

http://localhost:8190/userに対してuserIdというクエリパラメータを指定すると、userId、userName、emailの3つを含むレスポンスが返ってくることを表しています。

このようなファイルを自力で記述するのは大変ですが、既に実装したAPIから自動生成することもできます。
JavaのSpring Bootでの方法については、以下の記事の「OpenAPI仕様のドキュメントの自動生成」の部分を参考にしてください。

tech.excite.co.jp

このファイルにtest-api-docs.yamlという名前をつけて、プロジェクトルート内のspecsディレクトリに置いておきます。

依存関係の追加と設定を行う

自動生成を行う方法はいくつかありますが、今回はGradleのプラグインを利用します。

build.gradleは以下の通りです。

buildscript {
    repositories {
        mavenCentral()
    }

    dependencies {
        // OpenAPI Generatorのプラグイン
        classpath "org.openapitools:openapi-generator-gradle-plugin:7.2.0"
    }
}

plugins {
    id 'java'
    id 'org.springframework.boot' version '3.2.1'
    id 'io.spring.dependency-management' version '1.1.4'

}

apply plugin: 'org.openapi.generator'

group = 'com.example'
version = '0.0.1-SNAPSHOT'

java {
    sourceCompatibility = '21'
}

repositories {
    mavenCentral()
}

dependencies {
    implementation 'org.springframework.boot:spring-boot-starter'
    implementation 'org.springframework.boot:spring-boot-starter-web'
    testImplementation 'org.springframework.boot:spring-boot-starter-test'
}

tasks.named('test') {
    useJUnitPlatform()
}

基本的には、OpenAPI Generatorのプラグインを入れているだけです。

ここに、生成の際の設定を追加することができます。
build.gradleに以下のブロックを追加してください。

openApiGenerate {
    generatorName.set("java")
    inputSpec.set("$rootDir/specs/test-api-docs.yaml")
    outputDir.set("$projectDir/clientgen")
    apiPackage.set("com.example.clientgen.api")
    invokerPackage.set("com.example.clientgen.invoker")
    modelPackage.set("com.example.clientgen.model")
    configOptions.set([
         groupId: "com.example",
         artifactVersion: "0.0.1-SNAPSHOT",
    ])
}

それぞれの設定項目を解説していきます。

generatorNameGeneratorのリストにある、Generator名のどれかを設定します。
今回は、JavaAPIクライアントを生成したいので、javaを設定しています。

inputSpecoutputDirはそれぞれ生成に利用するOpenAPIのフォーマットに沿ったファイルのパスと、生成するコードの出力ディレクトリを指定します。

apiPackage, invokerPackage, modelPackageには生成するコードを出力する具体的なパッケージを設定します。

これらはOpenAPI GeneratorのGradleプラグインの設定項目であり、その他の設定項目はOpenAPI GeneratorのGradleプラグインの公式ドキュメントにあります。

反対にconfigOptionsでは、OpenAPI GeneratorでJavaクライアントを生成する際の共通の設定を行なえます。

groupIdartifactVersionは、生成されるbuild.gradlepom.xmlファイル内に記述されるgroupIdversionに対応しています。

他にも様々な設定項目が用意されていますので、詳細は公式ドキュメントをご確認ください。

実際に生成してみる

ここまで記述できたら、Gradleプロジェクトのビルドを行います。

./gradlew build

ビルドが完了すると、OpenAPI GeneratorのGradleプラグインにより、openApiGenerateというタスクが実行可能になっています。
これを実行すると、outputDirに設定したディレクトリ(ここではclientgen)に自動生成ファイルが生成されます(ディレクトリが存在しない場合は作成される)。

./gradlew openApiGenerate

clientgenディレクトリには、主に自動生成されたクライアント自体の依存関係が記述されたbuild.gradlepom.xmlと、実際のコードが含まれるsrcディレクトリがあります。
srcディレクトリ内を辿ると、api, invoker, modelの3つがあり、それぞれ以下のようなコードが存在しています。

  • api : test-api-docs.yamlから生成されたAPI
  • invoker : HTTPクライアントや例外クラス、認証まわりなどの実際にAPIを呼び出すために必要なコード
  • model : APIのリクエストやレスポンスのためのモデル

なお、生成されるJavaコードやその依存するライブラリ等は、最新版よりやや古いものもあるため注意が必要です。

実際に使ってみる

生成したクライアントを最も手軽に利用する方法は、README.mdにあるようにMavenのローカルリポジトリにインストールする方法でしょう。
ローカルリポジトリMaven Centralのローカル版のようなものであり、デフォルトでは$HOME/.m2/repositoryにあります。

Mavenをインストールする必要があるので、まだインストールされていない方はこちらからインストールしてください。

outputDirに設定したディレクトリに移動し、以下のコマンドを実行してMavenのローカルリポジトリに生成したAPIクライアントをローカルリポジトリにインストールします。

mvn clean install 

build.gradleに以下を追記します。

〜〜 略 〜〜

repositories {
    mavenCentral()

    // ローカルリポジトリの設定
    mavenLocal()
}

〜〜 略 〜〜

dependencies {
    implementation 'org.springframework.boot:spring-boot-starter'
    implementation 'org.springframework.boot:spring-boot-starter-web'
    testImplementation 'org.springframework.boot:spring-boot-starter-test'

     // 依存関係を追加
    implementation "example.com:openapi-java-client:0.0.1-SNAPSHOT"
}

〜〜 略 〜〜

プロジェクトを再ビルドし、以下のようなコントローラーを作成します。

import com.example.clientgen.api.UserApi;
import com.example.clientgen.invoker.ApiException;
import com.example.clientgen.model.UserResponseDto;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class DemoController {

    @GetMapping("user")
    public String getUser() {
        try {
            final UserResponseDto response = new UserApi().getUser("11111111");

            return String.format("Name: %s, Email: %s", response.getUserName(), response.getEmail());
        } catch (ApiException e) {
            throw new RuntimeException(e);
        }
    }
}

SpringApplicationを起動し、/userにアクセスすることで、内部でAPIクライアントがtest-api-docs.yamlで記述したAPIを呼んでくれます。

結果は、例えば以下のようになるでしょう。

終わりに

OpenAPI Generatorを利用することで、API呼び出しコードを自動で生成してくれます。
Java以外の言語でも生成できるので、ぜひ活用してみてください。

別のブログで、自動生成されたものを実際に活用する方法を執筆する予定です。

では、また次回。

参考文献