How we streamlined frontend development with OpenAPI 🚀
Dmitrii Zakharov

Dmitrii Zakharov @senior-debugger

About: Lead Frontend Software Engineer // Happy coder and debugger

Location:
Slovenia, Ljubljana
Joined:
May 28, 2025

How we streamlined frontend development with OpenAPI 🚀

Publish Date: Jun 12
10 3

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 or fetch) 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
Enter fullscreen mode Exit fullscreen mode

Create a config file openapi/apiConfig.json with the following:

{
  "prefixParameterInterfaces": true,
  "supportsES6": true,
  "typescriptThreePlus": true
}
Enter fullscreen mode Exit fullscreen mode

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"
}
Enter fullscreen mode Exit fullscreen mode

⚠️ 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),
};
Enter fullscreen mode Exit fullscreen mode

Now calling an API is as simple as:

const { accessToken } = await ApiClient.user.access.login({
  appLoginPayloadDto: payload,
});
Enter fullscreen mode Exit fullscreen mode

🔍 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();
}
Enter fullscreen mode Exit fullscreen mode

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! 🚀

Comments 3 total

  • Nevo David
    Nevo DavidJun 12, 2025

    Nice, makes me want to go clean up my own mess of HTTP calls tbh.

  • Vida Khoshpey
    Vida Khoshpey Jun 13, 2025

    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?

    • Dmitrii Zakharov
      Dmitrii ZakharovJun 13, 2025

      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!)

Add comment