|
| 1 | +=============== |
| 2 | +TypeScript Quickstart |
| 3 | +=============== |
| 4 | + |
| 5 | +This guide introduces `Smithy TypeScript <https://github.com/smithy-lang/smithy-typescript>`_ with a simple working example of a |
| 6 | +generated server and client. |
| 7 | + |
| 8 | +For this example, imagine that you are the proud owner of a coffee shop. |
| 9 | +Your API allows your customers to order some *typescript* from their TypeScript applications. |
| 10 | +Users can use your SDK to list available coffees, order a coffee, and track the status of their order. |
| 11 | + |
| 12 | +.. admonition:: Review |
| 13 | + :class: tip |
| 14 | + |
| 15 | + If you are new to Smithy or just need a refresher on the basics, you may find it helpful to work through the |
| 16 | + Smithy :doc:`../quickstart`. |
| 17 | + |
| 18 | +------------- |
| 19 | +Prerequisites |
| 20 | +------------- |
| 21 | + |
| 22 | +* :doc:`Smithy CLI <../guides/smithy-cli/cli_installation>` |
| 23 | +* `Node.js (>= 16) <https://nodejs.org/en/download>`_ and `yarn <https://yarnpkg.com/getting-started/install>`_ |
| 24 | +* Ensure you have the Smithy CLI installed. Run ``smithy --version`` to confirm the CLI is correctly installed. |
| 25 | + If you need to install the CLI, see :doc:`Smithy CLI Installation <../guides/smithy-cli/cli_installation>`. |
| 26 | +.. warning:: This project was made for Mac/Linux, it may not build correctly on Windows. |
| 27 | + |
| 28 | +------ |
| 29 | +Set Up |
| 30 | +------ |
| 31 | + |
| 32 | +Clone the `quickstart example template <https://github.com/smithy-lang/smithy-examples/tree/main/smithy-typescript-examples/quickstart-typescript>`_ |
| 33 | +using the Smithy CLI ``init`` command and change to the cloned directory: |
| 34 | + |
| 35 | +.. code-block:: sh |
| 36 | +
|
| 37 | + smithy init -t smithy-typescript-quickstart && cd smithy-typescript-quickstart |
| 38 | +
|
| 39 | +The directory tree of the project should look like: |
| 40 | + |
| 41 | +.. code-block:: sh |
| 42 | +
|
| 43 | + smithy-typescript-quickstart/ |
| 44 | + ├── smithy |
| 45 | + │ ├── ... |
| 46 | + ├── client |
| 47 | + │ ├── ... |
| 48 | + ├── server |
| 49 | + │ ├── ... |
| 50 | + ├── README.md |
| 51 | + └── ... |
| 52 | +
|
| 53 | +The example project contains a number of packages: |
| 54 | + |
| 55 | +* ``smithy/``: Common package for the service API model. Used by both client and server packages. |
| 56 | +* ``server/``: Code generated Server that implements stubbed operations code-generated from the service model. |
| 57 | +* ``client/``: Code generated client that can call the server. |
| 58 | + |
| 59 | + |
| 60 | +------------- |
| 61 | +Service Model |
| 62 | +------------- |
| 63 | + |
| 64 | +The Smithy API model for our service can be found in the model package. This model defines the interface of our service and |
| 65 | +guides the generation of client and server code. |
| 66 | + |
| 67 | +The service provides a few capabilities: |
| 68 | + |
| 69 | +* Get a menu of available coffees with descriptions |
| 70 | +* The ability to order a coffee. |
| 71 | +* The ability to check the status of an order. |
| 72 | + |
| 73 | +The service has the ``@restJson1`` protocol trait applied indicating that the service supports the :ref:`AWS restJson1 protocol <aws-restjson1-protocol>`. |
| 74 | + |
| 75 | +.. code-block:: smithy |
| 76 | + :caption: smithy/model/weather.smithy |
| 77 | +
|
| 78 | + /// Allows users to retrieve a menu, create a coffee order, and |
| 79 | + /// and to view the status of their orders |
| 80 | + @title("Coffee Shop Service") |
| 81 | + @restJson1 |
| 82 | + service CoffeeShop { |
| 83 | + ... |
| 84 | + } |
| 85 | +
|
| 86 | +Protocols define the rules and conventions for serializing and de-serializing data when communicating between |
| 87 | +client and server. |
| 88 | + |
| 89 | +Services can support multiple protocols at once. |
| 90 | + |
| 91 | +From the root of the example project, build the service model using Gradle: |
| 92 | + |
| 93 | +.. code-block:: sh |
| 94 | +
|
| 95 | + ./gradlew clean build |
| 96 | +
|
| 97 | +------------------- |
| 98 | +Running the project |
| 99 | +------------------- |
| 100 | + |
| 101 | +First, start the coffee shop service by executing the following command under ``server`` directory: |
| 102 | + |
| 103 | +.. code-block:: sh |
| 104 | +
|
| 105 | + yarn setup && yarn start |
| 106 | +
|
| 107 | +This will start the coffee shop server on port ``8888`` and log the following to the console: |
| 108 | + |
| 109 | +.. code-block:: sh |
| 110 | + :caption: terminal output |
| 111 | +
|
| 112 | + Started server on port 8888... |
| 113 | + handling orders... |
| 114 | +
|
| 115 | +To confirm the service is working, request the menu: |
| 116 | + |
| 117 | +.. code-block:: sh |
| 118 | +
|
| 119 | + curl localhost:8888/menu |
| 120 | +
|
| 121 | +This will return a JSON-formatted menu of coffee types that can be ordered from our cafe: |
| 122 | + |
| 123 | +.. code-block:: json |
| 124 | +
|
| 125 | + { |
| 126 | + "items": [ |
| 127 | + { |
| 128 | + "type": "DRIP", |
| 129 | + "description": "A clean-bodied, rounder, and more simplistic flavour profile.\nOften praised for mellow and less intense notes.\nFar less concentrated than espresso.\n" |
| 130 | + }, |
| 131 | + { |
| 132 | + "type": "POUR_OVER", |
| 133 | + "description": "Similar to drip coffee, but with a process that brings out more subtle nuances in flavor.\nMore concentrated than drip, but less than espresso.\n" |
| 134 | + }, |
| 135 | + { |
| 136 | + "type": "LATTE", |
| 137 | + "description": "A creamier, milk-based drink made with espresso.\nA subtle coffee taste, with smooth texture.\nHigh milk-to-coffee ratio.\n" |
| 138 | + }, |
| 139 | + { |
| 140 | + "type": "ESPRESSO", |
| 141 | + "description": "A highly concentrated form of coffee, brewed under high pressure.\nSyrupy, thick liquid in a small serving size.\nFull bodied and intensely aromatic.\n" |
| 142 | + } |
| 143 | + ] |
| 144 | + } |
| 145 | +
|
| 146 | +.. tip:: |
| 147 | + |
| 148 | + Use the ``jq`` command line utility to pretty-print the output of the ``curl`` command above. |
| 149 | + |
| 150 | +You may stop the server with ``CTRL + C`` in the terminal where it is running. |
| 151 | +With the server running, we can now call it with our client application. |
| 152 | +In a separate terminal, execute the client application under ``client`` directory : |
| 153 | + |
| 154 | +.. code-block:: sh |
| 155 | +
|
| 156 | + yarn setup && yarn start |
| 157 | +
|
| 158 | +The client application will use a code-generated TypeScript SDK for the coffee shop service to: |
| 159 | + |
| 160 | +1. Create a new coffee order for a refreshing COLD_BREW coffee, |
| 161 | +2. Wait a few seconds for the order to complete, and |
| 162 | +3. Call the service again to get the order. |
| 163 | + |
| 164 | +The client terminal will print the following to the console (your order ID will differ): |
| 165 | + |
| 166 | +.. code-block:: sh |
| 167 | + :caption: terminal output |
| 168 | +
|
| 169 | + Created request with id = 64a28313-c742-4442-a3ba-761111dea568 |
| 170 | + Got order with id = 64a28313-c742-4442-a3ba-761111dea568 |
| 171 | + Waiting for order to complete.... |
| 172 | + Completed Order:{id:64a28313-c742-4442-a3ba-761111dea568, coffeeType:COLD_BREW, status:COMPLETED} |
| 173 | +
|
| 174 | +---------------------------- |
| 175 | +Make a change to the service |
| 176 | +---------------------------- |
| 177 | + |
| 178 | +In this section, you will update the Coffee shop server application to support additional functionality. |
| 179 | +We would like to add a new operation to our service that allows users to get the hours of our cafe. |
| 180 | + |
| 181 | +The new operation, ``GetHours``, should be bound directly to our service shape, take no input, and should return an output |
| 182 | +with both the opening and closing times. We will host this operation on the route ``/hours`` , and the reported hours |
| 183 | +will be expressed in hours using 24hr time (i.e. 1PM is 13). |
| 184 | + |
| 185 | +Model Update |
| 186 | +============ |
| 187 | + |
| 188 | +First, the new operation must be added to our service model in the smithy package: |
| 189 | + |
| 190 | +.. code-block:: diff |
| 191 | + :caption: smithy/model/main.smithy |
| 192 | +
|
| 193 | + service CoffeeShop { |
| 194 | + version: "2024-08-23" |
| 195 | + operations: [ |
| 196 | + GetMenu, |
| 197 | + + GetHours |
| 198 | + ] |
| 199 | + resources: [ |
| 200 | + Order |
| 201 | + ] |
| 202 | + } |
| 203 | +
|
| 204 | +Then add the operation shape definition: |
| 205 | + |
| 206 | +.. code-block:: |
| 207 | + :caption: smithy/model/main.smithy |
| 208 | +
|
| 209 | + /// Retrieve the coffee shop hours. |
| 210 | + @http(method: "GET", uri: "/hours") |
| 211 | + @readonly |
| 212 | + operation GetHours{ |
| 213 | + output := { |
| 214 | + opensAt: Hour |
| 215 | + closesAt: Hour |
| 216 | + } |
| 217 | + } |
| 218 | +
|
| 219 | + // Hours for a day expressed in 24hr time |
| 220 | + @range(min: 0, max: 24) |
| 221 | + integer Hour |
| 222 | +
|
| 223 | +Server Update |
| 224 | +============= |
| 225 | + |
| 226 | +With our service model updated, we need to add the new functionality to our server. First, rebuild the project under the root directory: |
| 227 | + |
| 228 | +.. code-block:: sh |
| 229 | +
|
| 230 | + ./gradlew clean build |
| 231 | +
|
| 232 | +Let's try to start our server: |
| 233 | + |
| 234 | +.. code-block:: sh |
| 235 | +
|
| 236 | + cd server && yarn start |
| 237 | +
|
| 238 | +This will fail with a compilation error: |
| 239 | + |
| 240 | +.. code-block:: sh |
| 241 | + :caption: ``build`` output |
| 242 | +
|
| 243 | + src/CoffeeShop.ts:14:14 - error TS2420: Class 'CoffeeShop' incorrectly implements interface 'CoffeeShopService<CoffeeShopContext>'. |
| 244 | + Property 'GetHours' is missing in type 'CoffeeShop' but required in type 'CoffeeShopService<CoffeeShopContext>'. |
| 245 | +
|
| 246 | +
|
| 247 | +Smithy TypeScript **requires** that an implementation of a generated operation interface be registered with the server for |
| 248 | +every operation defined in service model. Let’s add the required implementation: |
| 249 | + |
| 250 | +.. code-block:: TypeScript |
| 251 | + :caption: server/src/CoffeeShop.ts |
| 252 | +
|
| 253 | + async GetHours(context: CoffeeShopContext): Promise<GetHoursOutput> { |
| 254 | + return { |
| 255 | + opensAt: 9, |
| 256 | + closesAt: 16 |
| 257 | + } |
| 258 | + } |
| 259 | +
|
| 260 | +Now, re-start our server: |
| 261 | + |
| 262 | +.. code-block:: sh |
| 263 | +
|
| 264 | + yarn start |
| 265 | +
|
| 266 | +Finally, we can test the new operation using curl: |
| 267 | + |
| 268 | +.. code-block:: sh |
| 269 | +
|
| 270 | + curl localhost:8888/hours |
| 271 | +
|
| 272 | +Which will return the hours of our Cafe: |
| 273 | + |
| 274 | +.. code-block:: java |
| 275 | + :caption: ``curl`` output |
| 276 | +
|
| 277 | + {"opensAt":9,"closesAt":16} |
| 278 | +
|
| 279 | +Client Update |
| 280 | +============= |
| 281 | + |
| 282 | +What if we want to call our new operation from our client application? |
| 283 | +The client code generator will automatically add the ``getHours`` operation to the generated client, |
| 284 | +we just need to call it in our client application: |
| 285 | + |
| 286 | +.. code-block:: diff |
| 287 | + :caption: client/src/index.js |
| 288 | +
|
| 289 | + async function main() { |
| 290 | + try { |
| 291 | + + const hours = await client.getHours() |
| 292 | + + console.log(`Hours: Opens at: ${hours["opensAt"]}, Closes at ${hours["closesAt"]}`) |
| 293 | + // Create an order request |
| 294 | + const createRequest: CreateOrderInput = { |
| 295 | + coffeeType: CoffeeType.COLD_BREW |
| 296 | + }; |
| 297 | +
|
| 298 | +With the server still running, call our client one more time: |
| 299 | + |
| 300 | +.. code-block:: sh |
| 301 | +
|
| 302 | + yarn start |
| 303 | +
|
| 304 | +A new log line will now appear, listing the cafe’s hours: |
| 305 | + |
| 306 | +.. code-block:: sh |
| 307 | + :caption: terminal output |
| 308 | +
|
| 309 | + Hours: Opens at: 9, Closes at: 16 |
| 310 | +
|
| 311 | +---------- |
| 312 | +Next steps |
| 313 | +---------- |
| 314 | + |
| 315 | +* Discover the Smithy ecosystem: `Awesome-Smithy <https://github.com/smithy-lang/awesome-smithy>`_ |
0 commit comments