Search code examples
javaamazon-web-servicesaws-cdk

CDK ApiGateway JsonSchema from Java class


Has anyone figured out a way to generate the software.amazon.awscdk.services.apigateway.JsonSchema from a Java class for CDK?

It would be so nice not to have to manually do it for all the classes.

Something like:

import software.amazon.awscdk.services.apigateway.RestApi;
import software.amazon.awscdk.services.apigateway.JsonSchema;
import com.github.victools.jsonschema.generator.SchemaGenerator;
import com.github.victools.jsonschema.generator.SchemaGeneratorConfig;
import com.github.victools.jsonschema.generator.SchemaGeneratorConfigBuilder;
import my.java.project.domains.models.MyClass;

SchemaGeneratorConfigBuilder configBuilder = new SchemaGeneratorConfigBuilder(SchemaVersion.DRAFT_7, OptionPreset.PLAIN_JSON);
SchemaGeneratorConfig config = configBuilder.with(Option.EXTRA_OPEN_API_FORMAT_VALUES)
    .without(Option.FLATTENED_ENUMS_FROM_TOSTRING)
    .build();
    
SchemaGenerator schemaGenerator = new SchemaGenerator(config);
String schemaString = SchemaBuilder.buildSchema(MyClass.class);

RestApi myRestApi = RestApi.Builder.create(this, "MyRestApi")
    .restApiName("myRestApi")
    .deployOptions(StageOptions.builder()
                    .stageName("v1")
                    .tracingEnabled(true)
                    .build())
    .build();

IModel myRequestModel = Model.Builder.create(this, "MyRequestModel")
    .restApi(myRestApi)
    .contentType("application/json")
    .description("Reset password request model")
    .schema(JsonSchema.builder().fromString(schemaString)) <--------------
    .build();

Solution

  • Hot damn! I figured it out. I remembered you have access to the lowest CloudFormation constructs.

    So this is how. Step 1: Generate the schema from your model

    SchemaGeneratorConfigBuilder configBuilder = new SchemaGeneratorConfigBuilder(SchemaVersion.DRAFT_7, OptionPreset.PLAIN_JSON);
    SchemaGeneratorConfig config = configBuilder.with(Option.EXTRA_OPEN_API_FORMAT_VALUES)
        .without(Option.FLATTENED_ENUMS_FROM_TOSTRING)
        .build();
    SchemaGenerator schemaGenerator = new SchemaGenerator(config);
    var schema = schemaGenerator.generateSchema(MyClass.class);
    

    Step 2: Create a CfnModel class from the schema Object

    CfnModel cfnModel = CfnModel.Builder.create(this, "MyRequestModel")
        .restApiId(myRestApi.getRestApiId())
        .contentType("application/json")
        .description("My Request Model")
        .name("MyRequestModel")
        .schema(schema)
        .build();
    

    Step 3: Use Model.fromModelName when attaching the model to the method

    myRestApi.getRoot()
        .resourceForPath("/my/path")
        .addMethod(HttpMethod.POST.toString(), ...,
            MethodOptions.builder()
                ...
                .requestModels(Map.of("application/json", Model.fromModelName(this, "MyRequestModel", cfnModel.getName())))
                ...
    

    I haven't run cdk deploy yet but it did cdk synth without a problem and the CloudFormation template is correct.