Many of you have probably used OpenAPI in your projects, or at least heard of it. But from my regular conversations with developers, Iโve noticed something surprising: a lot of frontend developers still donโt fully take advantage of it.
This article is about how using OpenAPI has helped us speed up development, improve code consistency, and eliminate entire categories of errors. I'll also walk you through how to set it up and integrate it into a TypeScript project.
๐งฉ What Is OpenAPI, really?
At its core, OpenAPI is a tool that takes your Swagger definitions and generates a full API client, including:
- A wrapper for all your endpoints
- Typed models and DTOs (based on Swagger schema)
- Methods that handle requests for you (like
axios
orfetch
) with built-in type safety
In short: no more manually writing interfaces and HTTP calls. You get a fully typed, ready-to-use client thatโs always in sync with the backend.
๐ก Why OpenAPI matters
Here are some of the biggest benefits weโve seen:
- Type safety out of the box: All request and response models are generated from Swagger. You no longer need to manually define interfaces or worry about mismatches.
- No more manual fetch/axios calls: All endpoints come with pre-written request methods.
- Consistency between backend and frontend: When something changes on the backend (e.g., a route is renamed or a payload changes), you just re-generate the schema and catch issues during compile time.
- Zero maintenance: Once configured, itโs basically plug-and-play โ just update the schema when needed.
๐ Setting up OpenAPI in your project
To get started, install the OpenAPI generator:
yarn add @openapitools/openapi-generator-cli
Create a config file openapi/apiConfig.json
with the following:
{
"prefixParameterInterfaces": true,
"supportsES6": true,
"typescriptThreePlus": true
}
Now, add scripts to your package.json
:
"scripts": {
"openapi": "yarn openapi:download && yarn openapi:generate",
"openapi:download": "curl https://yourserver.com/api/docs-json > ./openapi/openapi.json",
"openapi:generate": "openapi-generator-cli validate -i ./openapi/openapi.json && rm -rf src/openapi/api && openapi-generator-cli generate -i ./openapi/openapi.json -c ./openapi/apiConfig.json -g typescript-fetch -o src/openapi/api"
}
โ ๏ธ Note: You may need to install JRE (Java Runtime Environment) for the generator to work.
๐ฆ Building the API Client
After running yarn openapi
, youโll get a fully generated src/openapi
folder with models, APIs, and types.
To simplify usage, letโs build a centralized API client:
import {
BonusApi,
ChatApi,
Configuration,
ServiceApi,
UserAccessApi,
UserInfoApi,
UsersApi,
UserTasksApi,
UserUtilsApi,
} from './api';
const configuration = new Configuration({
accessToken() {
return 'ACCESS_TOKEN';
},
get headers() {
return {
'x-language': 'en',
};
},
});
export const ApiClient = {
chat: new ChatApi(configuration),
service: new ServiceApi(configuration),
user: {
access: new UserAccessApi(configuration),
info: new UserInfoApi(configuration),
tasks: new UserTasksApi(configuration),
utils: new UserUtilsApi(configuration),
},
users: new UsersApi(configuration),
};
Now calling an API is as simple as:
const { accessToken } = await ApiClient.user.access.login({
appLoginPayloadDto: payload,
});
๐ Whatโs under the hood?
Letโs take a look at the actual implementation of the login
method:
async loginRaw(
requestParameters: UserAccessApiLoginRequest,
initOverrides?: RequestInit | runtime.InitOverrideFunction
): Promise<runtime.ApiResponse<AppAccessUserTokenDto>> {
if (requestParameters['appLoginPayloadDto'] == null) {
throw new runtime.RequiredError('appLoginPayloadDto', 'Required parameter is missing.');
}
const headerParameters: runtime.HTTPHeaders = {
'Content-Type': 'application/json',
};
const response = await this.request({
path: `/app/user/access/login`,
method: 'POST',
headers: headerParameters,
body: AppLoginPayloadDtoToJSON(requestParameters['appLoginPayloadDto']),
}, initOverrides);
return new runtime.JSONApiResponse(response, (jsonValue) => AppAccessUserTokenDtoFromJSON(jsonValue));
}
async login(
requestParameters: UserAccessApiLoginRequest,
initOverrides?: RequestInit | runtime.InitOverrideFunction
): Promise<AppAccessUserTokenDto> {
const response = await this.loginRaw(requestParameters, initOverrides);
return await response.value();
}
You can see that everything is strictly typed โ parameters, return values, and even runtime checks are in place.
โ ๏ธ Limitations (for now)
There are still some things OpenAPI doesnโt support out of the box, such as:
- WebSockets
- Some custom middleware logic
These require custom solutions for now. But the OpenAPI ecosystem is rapidly evolving, and we expect more features to be supported over time.
See you in the comments โ and thanks for reading! ๐
Top comments (3)
Nice, makes me want to go clean up my own mess of HTTP calls tbh.
The problem is that , openai is very expensive, my country is under embargo and I can't even use it for a month for free. Ready-made models are the only way. Do you have any suggestions for me in this regard?
You probably got it mixed up; it's not OpenAI, but OpenAPI, and it's available for all regions worldwide via npm storage.
Have a good day!)