OpenAPI / Swagger is a good way to describe API contracts between backend / frontend or different services. Nowadays frontend is almost always TypeScript + some framework (React, Vue, Angular, etc). Backend in turn can be in NodeJS (and then in principle you can share contracts with code reuse), or in another language (e.g. Python / Go / Scala / Rust) and then code reuse and API synchronization becomes a problem.
OpenAPI can solve this problem through codegen – backend should qualitatively describe the available API methods and data types, after that you can use the client generation utility and get ready typed TypeScript code.
OpenAPI has a standard tool for such generation, but it has a number of problems:
- Tool is written in Java, which requires special software to be installed on dev computer / CI
- Generate client is extensive and consists of many
.ts
files, which makes it not user friendly (in my opinion)
In JavaScript ecosystem it is common to use npm (or yarn / pnpm – whatever you like more) as a package manager. But the point is the same: packages are written in JavaScript, installed from one place, versioned.
In npm you can find several alternative apigen utilities written in TypeScript which provides a better development experience. I used one of those too (swagger-typescript-api), until they changed interfaces a few times and I had to fix my several projects. I tried to find an alternative in npm, but all available generators (as of late 2023) also have their own problems: generate a lot of files, are difficult to configure, break compatibility between versions, require to install additional packages.
Meet apigen-ts
I have a couple of projects in NestJS / FastAPI in support mode, for which I just need a stable API client generation utility that is simple and won't change often. So I wrote my own TypeScript HTTP API generation package from Swagger specification – apigen-ts.
Originally I wrote apigen-ts
for personal projects, but then I share it to my friends and they also started to use apigen-ts
in their projects. Now I want to share it with the community, maybe it will be useful for someone too. So library features:
- supports Swagger / OpenAPI v2 / v3 / v3.1 (parsed with redocly)
- generates a typed TypeScript client
- single output file, single api class
- exports data models for use in your code
- automatic code formatting with prettier (peer dependency)
- ability to automatic dates parsing
Usage
Usage is as simple as possible and is divided into two steps: generating a client from specification (local file or remote url; yaml or json), using the generated typed client in the app.
Generation of an arbitrary client can be performed by command:
npx -y apigen-ts https://petstore3.swagger.io/api/v3/openapi.json ./api-client.ts
Or you can install apigen-ts
as a dev dependency (npm i -D apigen-ts
) and create a task to generate the client in package.json
:
{
"name": "my-frontend",
"scripts": {
"apigen": "apigen-ts http://127.0.0.1:3000/docs-json ./api-client.ts --parse-dates && tsc --noEmit"
}
}
Then use: npm run apigen
or yarn apigen
.
Generated file contains a client class named ApiClient
and TypeScript types used in API endpoints. Next you can use them in app code in the following way:
import { ApiClient, Pet } from "./api-client";
const api = new ApiClient({
baseUrl: "https://example.com",
headers: { Authorization: "secret-token" },
});
// GET https://example.com/pet/findByStatus?status=sold
await api.pet.findPetsByStatus({ status: "sold" }); // -> Pet[]
Generator tries to create method names in format like {domain}.{operation}
. The types used in Swagger spec can be imported directly into code (in example above Pet
is generated type). This approach makes it easy to track changes in contract and fix the application code where types are updated or methods are changed (of course if you describe your Swagger well). Just run new api generation and check frontend code for errors afterwards with TypeScript.
Also apigen-ts
works well in CI pipelines, when on new commits to the backend part you run frontend api client generation and check code compatibility.
The generated client uses native fetch API (does not require additional packages) and can be used both in browser and NodeJS environment. If you use prettier
in your project, the generated client will be automatically formatted according to project settings.
More configuration options and customization abilities can be in readme.
Conclusion
Backend ↔ frontend (or backend ↔ backend) communication is monotonous and repetitive work from project to project. Do not waste time and effort on manual writing of api clients. Instead use simple tools to automate process and keep code quality.
You can support the project with a star ⭐️ or leave an issue / feature request on Github page.
Top comments (0)