In my previous tutorial, I built a simple REST API with Swagger documentation. Check it out:
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. 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 (CRA) with a TypeScript template, of course 💅
npx create-react-app react-mini-swagger-client --template typescript
Somewhere else, I have my previous 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.
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:
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:
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:
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:
<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 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, 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.
Mini example of swagger-typescript-api
This project was bootstrapped with Create React App.
npx create-react-app react-mini-swagger-client --template typescript
And API client was generated with swagger-typescript-api.
npx swagger-typescript-api -p http://127.0.0.1:5000/api/v1/swagger.json -o ./src/apiClient --modular
... while running flask-mini-rest app.
Run the app
In the project directory, you can run:
npm start
Runs the app in the development mode.
Open http://localhost:3000 to view it in the browser.
The page will reload if you make edits.
You will also see any lint errors in the console.
Top comments (1)
Thanks @own_alazzam10 . Unfortunately, link is broken