Skip to content

Using Smithy

You can use Smithy, an interface definition language (IDL) to model your APIs. To use Smithy, in TypeSafeApiProject, specify it as your model.language.

new TypeSafeApiProject({
  model: {
    language: ModelLanguage.SMITHY,
    options: {
      smithy: {
        serviceName: {
          namespace: 'com.mycompany',
          serviceName: 'MyApi',
        },
      },
    },
  },
  ...
});
TypeSafeApiProject.Builder.create()
        .model(ModelConfiguration.builder()
                .language(ModelLanguage.SMITHY)
                .options(ModelOptions.builder()
                        .smithy(SmithyModelOptions.builder()
                                .serviceName(SmithyServiceName.builder()
                                        .namespace("com.mycompany")
                                        .serviceName("MyApi")
                                        .build())
                                .build())
                        .build())
                .build())
        ...
        .build();
TypeSafeApiProject(
    model=ModelConfiguration(
        language=ModelLanguage.SMITHY,
        options=ModelOptions(
            smithy=SmithyModelOptions(
                service_name=SmithyServiceName(
                    namespace="com.amazon",
                    service_name="MyApi"
                )
            )
        )
    ),
    ...
)

Using the Smithy IDL

For more information on how use Smithy for writing models, refer to the Smithy documentation.

$version: "2"
namespace example.hello

use aws.protocols#restJson1

@title("A Sample Hello World API")

/// A sample smithy api
@restJson1
service Hello {
    version: "1.0"
    operations: [SayHello]
}

@readonly
@handler(language: "typescript")
@http(method: "GET", uri: "/hello")
operation SayHello {
    input := {
        @httpQuery("name")
        @required
        name: String
    }
    output := {
        @required
        message: String
    }
    errors: [ApiError]
}

@error("client")
structure ApiError {
    @required
    errorMessage: String
}

Splitting your model definition

You can split your model definition into multiple .smithy files, but ensure they are in the model/src/main/smithy folder. For example, you can structure your model as follows:

model/src/main/smithy/
    |_ operations/
        |_ say-hello.smithy
    |_ structures/
        |_ say-hello-input.smithy
        |_ say-hello-output.smithy
    |_ main.smithy

Defining shapes

You can reference any defined shape from any .smithy file in any other .smithy file, so long as it is defined in the same namespace.

If you wish to define shapes under different namespaces, you can import them with the use keyword, for example:

$version: "2"
namespace com.foo

structure Foo {
    member: String
}
$version: "2"
namespace com.bar

use com.foo#Foo

structure Bar {
    foo: Foo
}

Supported protocols

PDK only supports AWS restJson1 currently, so make sure your service is annotated with the @restJson1 trait.

Authorizers

Smithy supports adding API Gateway authorizers in the model itself. If you do not have the ARN of the user pool or lambda function for an authorizer while defining the model, we recommend adding the authorizer(s) in your API CDK construct.

Info

If you use Smithy generated clients, some authorizer traits such as sigv4 will include configuring the client for that particular method of authorization, so it is beneficial to define authorizers in the model.

Type Safe API supports specifying authorizers in both the model and the construct, but the construct will take precedence where the authorizer ID is the same.

Customizing the Smithy build

When you synthesize the TypeSafeApiProject, it will contain a model/smithy-build.json file which customises the Smithy build, such as its conversion to OpenAPI. You can customise this file by adjusting the model.options.smithy.smithyBuildOptions:

new TypeSafeApiProject({
  model: {
    language: ModelLanguage.SMITHY,
    options: {
      smithy: {
        serviceName: {
          namespace: 'com.mycompany',
          serviceName: 'MyApi',
        },
        // Use smithyBuildOptions to control what is added to smithy-build.json.
        smithyBuildOptions: {
          projections: {
            // You can customise the built-in openapi projection, used to generate the OpenAPI specification.
            openapi: {
              plugins: {
                openapi: {
                  // Customise the openapi projection here.
                  // See: https://smithy.io/2.0/guides/converting-to-openapi.html
                  defaultTimestampFormat: "epoch-seconds",
                  ...
                }
              }
            },
            // You can add new projections here too
            "ts-client": {
              "plugins": {
                "typescript-codegen": {
                  "package" : "@my-test/smithy-generated-typescript-client",
                  "packageVersion": "0.0.1"
                }
              }
            }
          },
          // Note that any additional dependencies required for projections/plugins can be added here, which in turn will
          // add them to the `smithy/build.gradle` file
          maven: {
            dependencies: [
              "software.amazon.smithy:smithy-validation-model:1.27.2",
            ]
          }
        }
      },
    },
  },
  ...
});
 new TypeSafeApiProject(TypeSafeApiProjectOptions.builder()
        .name("myapi")
        .model(ModelConfiguration.builder()
                .language(ModelLanguage.SMITHY)
                .options(ModelOptions.builder()
                        .smithy(SmithyModelOptions.builder()
                                .serviceName(SmithyServiceName.builder()
                                        .namespace("com.mycompany")
                                        .serviceName("MyApi")
                                        .build())
                                // Use smithyBuildOptions to control what is added to smithy-build.json.
                                .smithyBuildOptions(SmithyBuildOptions.builder()
                                        .projections(Map.of(
                                            // You can customise the built-in openapi projection, used to generate the OpenAPI specification.
                                            "openapi", SmithyProjection.builder()
                                                    .plugins(Map.of(
                                                            "openapi", Map.of(
                                                                "defaultTimestampFormat", "epoch-seconds"
                                                            )
                                                    ))
                                                    .build(),
                                            // You can add new projections here too
                                            "ts-client", SmithyProjection.builder()
                                                    .plugins(Map.of(
                                                            "typescript-codegen", Map.of(
                                                                    "package", "@my-test/smithy-generated-typescript-client",
                                                                    "packageVersion", "0.0.1")
                                                    ))
                                                    .build()
                                            ))
                                        // Note that any additional dependencies required for projections/plugins can be added here, which in turn will
                                        // add them to the `smithy/build.gradle` file
                                        .maven(SmithyMavenConfiguration.builder()
                                                .dependencies(Arrays.asList("software.amazon.smithy:smithy-validation-model:1.27.2"))
                                                .build())
                                        .build()

                                ).build())
                                .build())
                        .build())
    ...
    .build();
TypeSafeApiProject(
    ModelConfiguration(
        language=ModelLanguage.SMITHY,
        options=ModelOptions(
            smithy=SmithyModelOptions(
                service_name=SmithyServiceName(
                    namespace="com.amazon",
                    service_name="MyApi"
                ),
                # Use smithyBuildOptions to control what is added to smithy-build.json.
                smithy_build_options=SmithyBuildOptions(
                    projections={
                        # You can customise the built-in openapi projection, used to generate the OpenAPI specification.
                        "openapi": SmithyProjection(
                            plugins={
                                "openapi": {
                                    # Customise the openapi projection here.
                                    # See: https://smithy.io/2.0/guides/converting-to-openapi.html
                                    "defaultTimestampFormat": "epoch-seconds"
                                }
                            }
                        ),
                        # You can add new projections here too
                        "ts-client": SmithyProjection(
                            plugins={
                                "typescript-codegen": {
                                    "package": "@my-test/smithy-generated-typescript-client",
                                    "package_version": "0.0.1"
                                }
                            }
                        )
                    },
                    # Note that any additional dependencies required for projections/plugins can be added here, which in turn will
                    # add them to the `smithy/build.gradle` file
                    maven=SmithyMavenConfiguration(
                        dependencies=["software.amazon.smithy:smithy-validation-model:1.27.2"]
                    )
                )
            )
        )
    ),
    ...
)

Last update: 2024-10-30