SaaSus PlatformのJava版SDK作成

こんにちは、Anti-Pattern Inc.の塚本です。

β版ですが、SaaSus PlatformのJava版SDKが公開されておりますので、ご紹介をしようと思います。
https://github.com/saasus-platform/saasus-sdk-java/

SaaSus PlatformのバックエンドはOpenAPIを利用してます。
また、マイクロサービス(モジュール)で設計されているのでその単位にYAMLファイルが存在します。

SDKは、その定義ファイルであるYAMLファイルからopenapi-generator-cliを使用して、自動生成します。
https://github.com/OpenAPITools/openapi-generator-cli

自動生成すると、モジュール単位にApiClientクラスが生成されます。
このApiClientは、OkHttpClient httpClientを内包していて、このhttpClientを利用してSaaSus Platformへのリクエストを処理されます。

ただし、このままでは利用できません。
SaaSus Platformへリクエストを送信するためには、リクエストヘッダーに署名をつける必要があります。

自動生成されたApiClientクラスのコンストラクタに、リクエストヘッダに設定する処理がありますが、
SaaSus Platformの署名はリクエストbody情報も使っているので、ApiClientクラスのインスタンス生成時には設定できません。

    /**
     * Basic constructor for ApiClient
     */
    public ApiClient() {
        init();
        initHttpClient();

        // Setup authentications (key: authentication name, value: authentication).
        authentications.put("Bearer", new HttpBearerAuth("bearer"));
        // Prevent the authentications from being modified.
        authentications = Collections.unmodifiableMap(authentications);
    }

署名の設定

そのために、リクエストを送信する直前で署名を設定する実装にしてます。

  • ApiClientを継承したクラスを定義
  • ApiClientクラスのexecuteをOverrideしたメソッドを定義
  • ApiClientを継承したクラスでheaderに署名を設定
  • 基底クラスApiClientのexecuteに処理を戻す

Callでリクエスト情報を操作できるので、リクエスト情報を使用して署名を作ることができます。
signature = Utils.withSaasusSigV1(call);
署名の実装はこちら
https://github.com/saasus-platform/saasus-sdk-java/blob/48eec9f6680b5b9dc854d7c7d629b7d59e03bbd2/src/main/java/saasus/sdk/modules/Utils.java#L17

package saasus.sdk.modules;

import saasus.sdk.auth.ApiClient;
import saasus.sdk.auth.ApiException;
import saasus.sdk.auth.ApiResponse;
import okhttp3.Call;
import okhttp3.OkHttpClient;
import okhttp3.Request;

import java.lang.reflect.Type;

public class AuthApiClient extends ApiClient {
    
    private String referer;

    @Override
    public <T> ApiResponse<T> execute(Call call, Type returnType) throws ApiException {        

        String signature = "";
        try {
            signature = Utils.withSaasusSigV1(call);
        } catch (Exception e) {
            throw new ApiException(e);
        }

        OkHttpClient httpClient = getHttpClient();
        Request request = call.request();
        Request newRequest = request.newBuilder().header("Authorization", signature).header("Referer", this.getReferer()).build();
        Call newCall = httpClient.newCall(newRequest);
        return super.execute(newCall, returnType);
    }

    private String getReferer() {
        if (referer == null) {
            return "";
        }
        return referer;
    }

    public void setReferer(String referer) {
        this.referer = referer;
    }
}

各モジュール単位にApiClientが自動生成されるので、それらを操作できるクラスを定義します。

package saasus.sdk.modules;

public class Configuration {
    
    private static final AuthApiClient authApiClient = new AuthApiClient();
    private static final PricingApiClient pricingApiClient = new PricingApiClient();
    private static final ApiLogApiClient apiLogApiClient = new ApiLogApiClient();
    private static final AwsMarketplaceClient awsMarketplaceClient = new AwsMarketplaceClient();
    private static final BillingApiClient billingApiClient = new BillingApiClient();
    private static final CommunicationApiClient communicationApiClient = new CommunicationApiClient();
    private static final IntegrationApiClient integrationApiClient = new IntegrationApiClient();

    public Configuration() {
        String urlBase = System.getenv("SAASUS_API_URL_BASE");
        if (urlBase != null) {
            authApiClient.setBasePath(urlBase + "/v1/auth");
            pricingApiClient.setBasePath(urlBase + "/v1/pricing");
            apiLogApiClient.setBasePath(urlBase + "/v1/apilog");
            awsMarketplaceClient.setBasePath(urlBase + "/v1/awsmarketplace");
            billingApiClient.setBasePath(urlBase + "/v1/billing");
            communicationApiClient.setBasePath(urlBase + "/v1/communication");
            integrationApiClient.setBasePath(urlBase + "/v1/integration");
        }
    }

    public AuthApiClient getAuthApiClient() {
        return authApiClient;
    }

    public PricingApiClient getPricingApiClient() {
        return pricingApiClient;
    }

    public ApiLogApiClient getApiLogApiClient() {
        return apiLogApiClient;
    }

    public AwsMarketplaceClient getAwsMarketplaceClient() {
        return awsMarketplaceClient;
    }

    public BillingApiClient getBillingApiClient() {
        return billingApiClient;
    }

    public CommunicationApiClient getCommunicationApiClient() {
        return communicationApiClient;
    }

    public IntegrationApiClient getIntegrationApiClient() {
        return integrationApiClient;
    }
}

SDK使い方

  • Configurationクラスから利用するモジュールのApiClinetを取得
  • 取得したApiClinetを使用して、実行するApiクラスを生成
  • Apiの実行
    例えば、Auth APIの/userinfoを使用する場合はこのようになります。
    // AuthのApiClientを取得
    AuthApiClient apiClient = new Configuration().getAuthApiClient();

    // AuthのUserInfoApiをApiClientを使用して生成
    UserInfoApi userInfoApi = new UserInfoApi(apiClient);

    // tokenはrequestのAuthorizationからBearerを取得して設定
    userInfo = userInfoApi.getUserInfo(token);

実行可能なサンプルはこちらにあります。
https://github.com/saasus-platform/implementation-sample-api-java