Simplify Your API Development with Our OpenAPI Code Generation Tool

Simplify Your API Development with Our OpenAPI Code Generation Tool

·

6 min read

By Andrej Staš

The openapi-transformer-toolkit

As a developer, you may find yourself in a situation where you have an OpenAPI specification and need to create a JSON schema or TypeScript interfaces that reflect this specification.

Fortunately, there are a number of tools available that can help you automate this process. We have created our own solution on top of them called openapi-transformer-toolkit.

Why did we develop the openapi-transformer-toolkit?

While there are alternative libraries available for generating TypeScript interfaces and JSON schemas from OpenAPI specifications, we developed the openapi-transformer-toolkit for several reasons:

1. Separate TypeScript interface files

Alternative libraries like openapi-typescript and openapi-typescript-codegen output all TypeScript interfaces into a single file that reflects the OpenAPI schema. We based our solution on json-schema-to-typescript, but customized the output and our solution makes the generated interfaces unaware of the original OpenAPI schema.

2. Import existing TypeScript interfaces

Our toolkit also has the ability to automatically reuse already generated TypeScript interfaces in other generated interfaces, instead of duplicating them.

3. Separate JSON schema files

For JSON schema generation, we are reusing the openapi-schema-to-json-schema package, but we have customized the output to create a separate file for each JSON schema. This makes it easier to work with in some cases, as it allows for better organization and modularity.

4. Customizable logging

The openapi-transformer-toolkit uses the pino logger by default, which is a fast and versatile logging library. However, when using the toolkit programmatically, you have the option to set up a custom logger that suits your specific needs and preferences. This flexibility allows you to seamlessly integrate the toolkit into your existing logging infrastructure, ensuring a consistent and unified logging experience across your project.

Summary: automating and simplifying the generation of code from an OpenAPI specification

This toolkit is designed to simplify and automate the process of generating JSON schemas and TypeScript types based on an OpenAPI specification using CLI commands or programmatically in your code.

What is OpenAPI?

OpenAPI is a standardized, language-agnostic format for describing RESTful APIs using JSON or YAML. It enables the automatic generation of documentation, client libraries, and server stubs, improving consistency and reducing errors. The specification streamlines API development, integration, and maintenance, fostering better collaboration among developers.

How can you use JSON schemas in your project?

JSON schemas can improve data validation, documentation, and communication in a project. They help define data structure and constraints, enabling automatic validation and the generation of client and server-side code. JSON schemas also facilitate collaboration and easier integration with external systems.

How to use the openapi-transformer-toolkit?

You can start using the CLI commands for user-friendly access, or use the toolkit programmatically for increased flexibility.

Example of CLI Commands

Let’s test the first CLI command called oas2json. It will create a JSON schema based on the OpenAPI specification.

$ npx openapi-transformer-toolkit oas2json -i ./openapi.yml -o ./schemas

Let’s say this is our simple OpenAPI specification saved in openapi.yml file (JSON format is also supported).

openapi: 3.0.3
info:
  title: Example OpenAPI
  version: 1.0.11
paths: {}
components:
  schemas:
    Customer:
      type: object
      properties:
        id:
          type: integer
          format: int64
        username:
          type: string
        address:
          type: array
          items:
            $ref: '#/components/schemas/Address'
    Address:
      type: object
      properties:
        street:
          type: string
        city:
          type: string
        state:
          type: string
        zip:
          type: string

The command above will generate the following files:

Address.json file:

{
  "type": "object",
  "properties": {
    "street": {
      "type": "string"
    },
    "city": {
      "type": "string"
    },
    "state": {
      "type": "string"
    },
    "zip": {
      "type": "string"
    }
  },
  "title": "Address",
  "$id": "Address.json"
}

Customer.json file:

{
  "type": "object",
  "properties": {
    "id": {
      "type": "integer",
      "format": "int64",
      "minimum": -9223372036854776000,
      "maximum": 9223372036854776000
    },
    "username": {
      "type": "string"
    },
    "address": {
      "type": "array",
      "items": {
        "$ref": "Address.json"
      }
    }
  },
  "title": "Customer",
  "$id": "Customer.json"
}

Great! Now let’s create TypeScript interfaces. This time we will use the oas2ts command:

$ npx openapi-transformer-toolkit oas2ts -i ./openapi.yml -o ./types

And here’s the result, Address.d.ts:

export interface Address {
  street?: string;
  city?: string;
  state?: string;
  zip?: string;
  [k: string]: unknown;
}

And Customer.d.ts:

import { Address } from './Address'

export interface Customer {
  id?: number;
  username?: string;
  address?: Address[];
  [k: string]: unknown;
}

You can also generate TypeScript interfaces from the JSON schemas if you need to.

$ npx openapi-transformer-toolkit json2ts -i ./schemas -o ./types

Example of Programmatic Usage

You can also use the package programmatically by importing the necessary functions. First, let’s install the package in your project:

$ npm install openapi-transformer-toolkit

Now you can import the methods:

import { oas2json, oas2ts, json2ts } from 'openapi-transformer-toolkit';

You use them in a similar way to the CLI commands. So, to create JSON schemas from the OpenAPI specification, use the following code:

const openAPIPath = 'path/to/openapi.yml';
const schemasPath = 'path/to/output/schemas';

oas2json(openAPIPath, schemasPath);

You can create TypeScript files from the OpenAPI specification:

const openAPIPath = 'path/to/openapi.yml';
const tsTypesPath = 'path/to/output/types';

await oas2ts(openAPIPath, tsTypesPath);

Or you create TypeScript files from the JSON schemas, if you need to:

const schemasPath = 'path/to/output/schemas';
const tsTypesPath = 'path/to/output/types';

await json2ts(schemasPath, tsTypesPath);

Both functions would produce identical results (those shown above).

Using JSON Schemas in Fastify and React Hook Form

In this section, we’ll demonstrate how to use the generated JSON schemas in a Fastify server and a React application with the react-hook-form for form validation.

Getting Fastify to use the JSON schema to validate the incoming request body

import Fastify from 'fastify';
import CustomerSchema from './Customer.json' assert { type: 'json' };
import AddressSchema from './Address.json' assert { type: 'json' };

const fastify = Fastify({
    logger: true,
});

fastify.addSchema(CustomerSchema);
fastify.addSchema(AddressSchema);

fastify.post('/customer', {
        schema: {
            body: {
                $ref: 'Customer.json#',
            },
        },
    },
    async (request, reply) => {
        const customer = request.body;
        return { message: 'Customer created successfully', customer };
    }
);

fastify.listen({ port: 3000 });

Now your Fastify server will use the JSON schema to validate the incoming request body for the /customer endpoint.

Getting the React Hook Form to use the JSON schema to validate input fields

import React from 'react';
import { useForm } from 'react-hook-form';
import { yupResolver } from '@hookform/resolvers/yup';
import convertToYup from "json-schema-yup-transformer";
import AddressJson from "./Address.json";

const App = () => {
    const { register, handleSubmit, formState: {errors} } = useForm({
        resolver: yupResolver(convertToYup(AddressJson)),
    });

    const onSubmit = (data) => {
        console.log('Submitted data:', data);
    };

    return (
        <div>
            <h1>Address Form</h1>
            <form onSubmit={handleSubmit(onSubmit)}>
                <label htmlFor="street">Street</label>
                <input name="street" {...register("street")} />
                {errors.street && <p>{errors.street.message}</p>}
                <br />

                <label htmlFor="city">City</label>
                <input name="city" {...register("city")} />
                {errors.city && <p>{errors.city.message}</p>}
                <br />

                <label htmlFor="state">State</label>
                <input name="state" {...register("state")} />
                {errors.state && <p>{errors.state.message}</p>}
                <br />

                <label htmlFor="zip">ZIP Code</label>
                <input name="zip" {...register("zip")} />
                {errors.zip && <p>{errors.zip.message}</p>}
                <br />

                <button type="submit">Submit</button>
            </form>
        </div>
    );
};
export default App

In this example, we’ve used the Address.json schema to create an address form with the react-hook-form. The form will be validated using the schema, and errors will be displayed accordingly.

Ongoing enhancements

In the future, we aim to incorporate support for additional validation outputs, making the toolkit even more powerful and adaptable.

Conclusion

The OpenAPI Transformer Kit created by NearForm is a practical addition to your API development toolkit. It quickly streamlines the generation of JSON schemas and TypeScript types from OpenAPI specifications, allowing you to focus on the core aspects of crafting reliable APIs.

Give the OpenAPI Transformer Kit a try today and don’t hesitate to share your experience with us. We’re always open to your feedback and suggestions for future improvements.