DEV Community

Cover image for Type sharing in OpenAPI Fullstack projects
Jakub Andrzejewski
Jakub Andrzejewski

Posted on

Type sharing in OpenAPI Fullstack projects

From the very beginning of working in my current project, we have been experiencing an issue of code reusability across the Front and Back of our application. We had a lot of code that was duplicated and often also included issues that created problems for us later on.

At the beginning, we were focusing on developing new features nad functionalities, so things like Code Reusability had to be added to the Nice to Have list. But, this has changed recently and right now we have a budget and resources to work on improving our project and its development.

In this article, I would like to share with you how we have solved one of our problems -> Type Sharing. Thanks to that, you will be able to implement this or similiar solution from the very beginning of working in your project (or add it afterwards just as we did).

Code Reusability

The solutions has proven to be quite useful and with the addition of ~10 lines of code (mainly CI/CD scripts) we were able to reduce the amount of static TS code by hundreds of lines.

Enjoy!

Idea

Let's share a little background about the project technology stack, as the solution that I will talk about might not suit all projects (and most probably wont suit all of them).

The application is composed out of two main pillars:

  1. Vue 3 SPA Frontend application
  2. Nest.js REST Backend Modular Monolith

In both projects, we use TypeScript everywhere - from components & composables, to services & controllers.

On the backend, we are using Swagger to generate Open API documentation and playground.

This swagger can be configured to not only generate documentation but also the api.json file that contains all Open API schema that later on can be easily used in other tools.

For local development you can do something like this:

const document = SwaggerModule.createDocument(app, config);
writeFileSync('api.json', JSON.stringify(document))
Enter fullscreen mode Exit fullscreen mode

You can read more about this Swagger Module here https://docs.nestjs.com/openapi/introduction

Swagger

This newly generated file will contain all types and available operations for your Backend.

After generating this file, you can then consume it in your frontend application like this:

npx openapi-typescript ./backend/api.json -o ./frontend/schema.d.ts
Enter fullscreen mode Exit fullscreen mode

This will generate a schema file will all the types generated by the Open API specification. Magic 🪄

You can use it in your frontend application like following:

import { components } from '../../schema';

type User = components['schemas']['User']
Enter fullscreen mode Exit fullscreen mode

And you will have full type safety and autocompletion. When I first used it, I instantly felt that this is an amazing feature that could help us a lot.

Summary

This approach is not only about reusability and reducing the lines of code that need to be maintained. It is also about maintaining the contract between Frontend and the Backend. By using one type both in Front and Back, we are making sure that we are not missing any data or passing a wrong parameter name (which is also great for further updating the project types). You can read more about it https://pactflow.io/how-pact-works/?utm_source=ossdocs&utm_campaign=getting_started#slide-1

This is just an example. To make this work fully, you would probably need to also add this schema generation both on frontend and the backend to your CI/CD pipeline so that everything is done automatically and kept in sync :)

In my case, this solution helped a lot. I hope that it will help you as well!

Top comments (2)

Collapse
 
enkot profile image
Enkot

If you're using Nuxt, I recommend trying the nuxt-open-fetch module, which loads your OpenAPI schema and generates corresponding fetch composables/utils. It uses openapi-typescript under the hood.

Collapse
 
jacobandrewsky profile image
Jakub Andrzejewski

This is a good recommendation! Thanks Enkot! :)