How to generate a TypeScript client from a Swagger documented API
Tags: typescript, api, swagger, tutorial
Published: 2021-11-15 22:04:32

In my previous tutorial, I built a simple REST API with Swagger documentation. Check it out:

{% link https://dev.to/po5i/how-to-set-up-a-rest-api-in-flask-in-5-steps-5b7d %}

In this tutorial, I will generate a TypeScript client code based on the Swagger documentation and use it on a simple React application (it can be any front-end application).

Why we want to do something like this? First of all, it's better to have one a single source of truth for the contracts in our server-client architecture. Otherwise, one change can break all our consumers.

For this process, I'm gonna use [swagger-typescript-api](https://github.com/acacode/swagger-typescript-api). I've seen this tool constantly evolving throughout the last year, its maintainers are doing an awesome job.

First of all, I bootstrap a React app using [create-react-app](https://github.com/facebook/create-react-app) (CRA) with a TypeScript template, of course 💅

```bash
npx create-react-app react-mini-swagger-client --template typescript
```

Somewhere else, I have my previous [flask-mini-rest](https://github.com/po5i/flask-mini-rest) up and running in `localhost:5000`. (Recently I pushed some changes in order to support CORS and improve the Swagger model documentation).

CRA places all the source files inside `./src` directory, so I will generate my TS client there.

```bash
npx swagger-typescript-api -p http://127.0.0.1:5000/api/v1/swagger.json -o ./src/apiClient --modular
```

swagger-typescript-api is pretty cool, it can be run with `npx` and it support many flags documented in its repo. It generates 3 files for my API

File | Description
-- | --
`Items.ts` | It exports the main client to be used on our application. Each method of the `Items` class is one public endpoint. Types were read from the Swagger docs.
`data-contracts.ts` | Are the API models or return types.
`http-client.ts` | This is the code responsible to actually fetch the data to the server.

Let's start the development server:

```bash
npm start
```

---

Now it comes the interesting part. How to use the generated TS client. I'm going to write some simple examples on how to use the TS client in the `src/App.tsx` file which is the only one with the bootstrapped app logic.

Let's initialize the API client which is declared in the `Items.ts` module:

```ts
const api = new Items({
  baseUrl: "http://localhost:5000/api/v1",
});
```

If your app is running a in a production server, the `baseUrl` path should point to the appropriate API URL.

To get all the Items:

```ts
const res = await api.getItemsApi();
setItems(res.data);  // This set the response to the `items` state
```

Let's suppose we want to insert a new item in the API in a form button:

```tsx
<button
  onClick={async () => {
    const item: Item = {  // `Item` is imported from the data-contracts
      id,  // this is a variable with the form input
      name,  // this is a variable with the form input
    };
    await api.postItemsApi(item);
    props.setItems([...props.items, item]);
  }}
>
  Add
</button>
```

It's pretty similar with the `getItemApi` which gets a simple  Item resource.

As you can see, it's pretty simple to use, self-documented and strongly-typed. Having a well defined back-end contract you can ensure robustness and type-safety front-end communication. The types generated can be used in many ways, TypeScript [project references](https://www.typescriptlang.org/docs/handbook/project-references.html) for example. Types can be shared among many consumers. My friend and mentor, Fernanda, presented a great talk in this topic called [Don't Break the Contract: Keep Consistency with Full Stack Type Safety](https://www.youtube.com/watch?v=8bLYoLBhNI0), please give it a look.

Also, an automated job can generate the a new TS client triggered by some event. But still it's up to us to update the consumers. Hopefully the unit tests can detect breaking changes.

Check out a full working code in my repo. Sorry that I didn't follow all the best practices as I only wanted to show how to use this TS client.

{% github po5i/react-mini-swagger-client %}