.. _generating-a-client: =================== Generating a client =================== Smithy code generators are implemented as :ref:`smithy-build plugins ` that run when the Smithy model is built. The plugins generate the equivalent of packages in their respective languages, configured to be used by language idiomatic tooling. Add the Codegen Plugin ====================== TypeScript clients are generated by the ``typescript-codegen`` plugin. Configure the plugin by adding it to ``smithy-build.json``: .. code-block:: json :caption: smithy-build.json { "version": "1.0", "sources": ["model"], "plugins": { "typescript-codegen": { "package": "@weather-service/client", "packageVersion": "0.0.1" } } } In this case, we've configured the ``typescript-codegen`` plugin to generate a package named ``@weather-service/client`` with version ``0.0.1``. .. tab:: Smithy CLI .. code-block:: json :caption: smithy-build.json { "version": "1.0", "sources": ["model"], "maven": { "dependencies": [ "software.amazon.smithy.typescript:smithy-aws-typescript-codegen:__smithy_typescript_version__" ] }, "...": "..." } .. tab:: Gradle Next, add a build-time dependency on the code generator: .. tab:: Kotlin .. code-block:: kotlin :caption: build.gradle.kts dependencies { smithyBuild("software.amazon.smithy.typescript:smithy-aws-typescript-codegen:__smithy_typescript_version__") } .. tab:: Groovy .. code-block:: groovy :caption: build.gradle dependencies { smithyBuild 'software.amazon.smithy.typescript:smithy-aws-typescript-codegen:__smithy_typescript_version__' } .. important:: `smithy-aws-typescript-codegen` is used here because it provides a protocol generator for the :ref:`@aws.protocols#restJson1 ` protocol. As mentioned in :doc:`update-model`, code generators must know how to generate code for the specified protocol. .. tab:: Smithy CLI Now run ``smithy build`` to build the model and generate the code. The TypeScript package is written to the ``typescript-codegen`` directory: .. code-block:: . ├── build │ └── smithy │ └── source │ ├── build-info/ │ ├── model/ │ ├── sources/ │ └── typescript-codegen │ ├── LICENSE │ ├── package.json │ ├── src/ │ ├── tsconfig.cjs.json │ ├── tsconfig.es.json │ ├── tsconfig.json │ ├── tsconfig.types.json │ └── typedoc.json ├── model │ └── weather.smithy └── smithy-build.json .. tab:: Gradle Now run ``gradle build`` to build the model and generate the code. The TypeScript package is written to the ``typescript-codegen`` directory: .. tab:: Kotlin .. code-block:: . ├── build │ ├── smithyprojections │ │ └── weather-service │ │ └── source │ │ ├── build-info/ │ │ ├── model/ │ │ ├── sources/ │ │ └── typescript-codegen │ │ ├── LICENSE │ │ ├── package.json │ │ ├── src/ │ │ ├── tsconfig.cjs.json │ │ ├── tsconfig.es.json │ │ ├── tsconfig.json │ │ ├── tsconfig.types.json │ │ └── typedoc.json │ └── tmp ├── build.gradle.kts ├── model │ └── weather.smithy └── smithy-build.json .. tab:: Groovy .. code-block:: . ├── build │ ├── smithyprojections │ │ └── weather-service │ │ └── source │ │ ├── build-info/ │ │ ├── model/ │ │ ├── sources/ │ │ └── typescript-codegen │ │ ├── LICENSE │ │ ├── package.json │ │ ├── src/ │ │ ├── tsconfig.cjs.json │ │ ├── tsconfig.es.json │ │ ├── tsconfig.json │ │ ├── tsconfig.types.json │ │ └── typedoc.json │ └── tmp ├── build.gradle ├── model │ └── weather.smithy └── smithy-build.json Using the generated code ======================== The generated code is just a normal TypeScript package. Each time the model is built and the code generated, the TypeScript code also has to be compiled. The generated ``package.json`` contains scripts to do so: .. code-block:: json :caption: package.json "scripts": { "build": "concurrently 'yarn:build:cjs' 'yarn:build:es' 'yarn:build:types'", "build:cjs": "tsc -p tsconfig.cjs.json", "build:docs": "typedoc", "build:es": "tsc -p tsconfig.es.json", "build:types": "tsc -p tsconfig.types.json", "build:types:downlevel": "downlevel-dts dist-types dist-types/ts3.4", "clean": "rimraf ./dist-* && rimraf *.tsbuildinfo", "prepack": "yarn run clean && yarn run build" } This example creates a mono-repo using `Yarn Workspaces`_ that integrates building the Smithy model and generating the code into the development workflow. First, move the Smithy project into its own directory named ``smithy/``: .. tab:: Smithy CLI .. code-block:: . └── smithy ├── build ├── model └── smithy-build.json .. tab:: Gradle .. tab:: Kotlin .. code-block:: . └── smithy ├── build ├── build.gradle.kts ├── model └── smithy-build.json .. tab:: Groovy .. code-block:: . └── smithy ├── build ├── build.gradle ├── model └── smithy-build.json Next, create a ``package.json`` in the root of the project with the following contents: .. tab:: Smithy CLI .. code-block:: json :caption: package.json { "name": "weather-service", "scripts": { "generate": "cd smithy && gradle clean build", "build": "yarn workspace @weather-service/client build" }, "dependencies": { "@weather-service/client": "0.0.1" }, "private": true, "workspaces": [ "smithy/build/smithy/source/typescript-codegen" ] } .. tab:: Gradle .. code-block:: json :caption: package.json { "name": "weather-service", "scripts": { "generate": "cd smithy && gradle clean build", "build": "yarn workspace @weather-service/client build", }, "dependencies": { "@weather-service/client": "0.0.1" }, "private": true, "workspaces": [ "smithy/build/smithyprojections/smithy/source/typescript-codegen" ] } A few things to note: * The path under ``workspaces`` is the path to the root of the generated TypeScript package. * A ``generate`` script which builds the model, re-generating the code. * The ``build`` script compiles the generated TypeScript package, referred to by the name specified in the ``typescript-codegen`` plugin configuration in ``smithy-build.json``. * A dependency has been added on the generated TypeScript package, using the name and version specified in the ``typescript-codegen`` plugin configuration in ``smithy-build.json`` After making model updates, use ``yarn generate && yarn build`` to run the code generator and build the generated code. You will have to do this before using the client in this example, because the output directory path has changed after moving the Smithy project into the ``smithy`` directory. Finally, create an ``app.ts`` file to use the client: .. code-block:: typescript import { GetCityCommandInput, GetCityCommandOutput, Weather } from '@weather-service/client'; const client: Weather = new Weather({ endpoint: 'some-endpoint' }); const getCityInput: GetCityCommandInput = { cityId: 'foo' }; client.getCity(getCityInput).then((getCityOutput: GetCityCommandOutput) => { // TODO Handle response }); The ``typescript-codegen`` plugin has generated a client, ``Weather``, with methods for each of the operations, as well as types for the inputs and outputs of those operations. .. _Yarn Workspaces: https://classic.yarnpkg.com/en/docs/workspaces