From the exquisite penmanship of Mihai Badila 

What is OpenApi Specification?

 

OpenAPI Specification (formerly known as Swagger Specification) is a popular tool for creating, documenting, and implementing RESTful APIs. Using YAML or JSON, it standardizes API structure descriptions, including endpoints, formats, and authentication. This framework improves development by fostering clear team communication and consistency accross frontend and backend. Swagger also features an interactive UI for easier API understanding and testing. ([https://editor.swagger.io](https://editor.swagger.io/)).

 

Type generation from Swagger

 

A type generator is a tool that automatically generates code based on an OpenAPI specification. It can generate classes, interfaces, and data models that correspond to the API endpoints and data structures defined in the specification. This makes it easier and more efficient to work with the API in your preferred programming language.

To use a client generated by the type generator, you typically import the generated code into your project and use it to interact with the API. The client will provide methods that correspond to the different API endpoints, allowing you to make requests and receive responses in a simplified manner. This abstraction reduces the amount of boilerplate code you have to write and makes it easier to call the API endpoints as methods in your code.

Clients utilizing type generators often leverage operationIds to define methods corresponding to backend endpoints. This approach ensures that modifications in backend endpoints do not necessitate direct changes in the frontend code. Instead, by regenerating types from the Swagger documentation, updates occur automatically, maintaining alignment between the frontend and backend with minimal manual intervention. This method exemplifies a more efficient and streamlined process in synchronizing frontend and backend communication over HTTP.

 

Why Generate Types and Clients?

 

Generating types and clients from an openapi.json specification streamlines the development process in several ways:

  1. Type Safety: For TypeScript projects, generating types ensures that the data structures used in API requests and responses are type-safe, reducing runtime errors and improving developer confidence.
  2. Up-to-date Types: Automatically generating API types means that any changes in the backend API are quickly integrated into the frontend application, keeping the client up-to-date with minimal manual intervention.
  3. Consistency: A generated client enforces consistency in how API endpoints are accessed, making it easier for developers to understand and use the API correctly.
  4. Speed: Developers spend less time writing boilerplate code for API requests and handling responses, accelerating the development of new features.
  5. Documentation: Generated types often serve as a form of documentation, making the API self-explanatory and reducing the learning curve for new developers.

 

Generating Types

To showcase this the benefits of using this we can start with a react project and add openapi-client-axios along with its type generation tool, openapi-client-axios-typegen

 

Step-by-Step Type Generation

Assuming you already have a React project set up with TypeScript, follow these steps to generate types:

  1. Install Dependencies: Add openapi-client-axios and openapi-client-axios-typegen to your project using your preferred package manager. For this tutorial, we will use yarn.
  2.  

     yarn add openapi-client-axios

     yarn add -D openapi-client-axios-typegen
  3. Generate Types: Run the openapi-client-axios-typegen command, providing it with the path to your openapi.json. In this case, we will implement the petstore3 API offered by OAI.
  4.  typegen "https://petstore3.swagger.io/api/v3/openapi.json" -o src/Client.d.ts

    This command reads your OpenAPI definition and outputs a TypeScript file (Client.d.ts) in your project’s src directory, containing all the necessary types.

     

    Extra For easier usage, we can add that command as a new package script like this..

        // package.json
    {
    	...
    	"scripts":{
    		...
    		"generate-types": "typegen 'https://petstore3.swagger.io/api/v3/openapi.json' > src/Client.d.ts",
    		...	
    	}
    	...
    }
    
  5. Integrate Types:To make use of the previously generated types in our App we can import them like this
  6.  

    // App.tsx
    import { Components } from './Client.d';
    type Pet = Components.Schemas.Pet
    
    function App() {
    	//...App Contents
    }
    
    export default App;
    

     

    Defining a Separate API Client File

     

    Centralizing your API logic is a best practice. Here’s how you can define a separate file for your `openapi-client-axios` instance:

    1. Create a Client Instance: Set up an axios.ts file in your src directory. In this file, we will initialize the API and export a getClient method in which we will pass our Client type.

       

          // axios.ts
      import OpenAPIClientAxios from "openapi-client-axios";
      import { Client as PetStoreClient } from "./Client.d";
      
      const api = new OpenAPIClientAxios({
        definition: "https://petstore3.swagger.io/api/v3/openapi.json",
        withServer: { url: "https://petstore3.swagger.io/api/v3" },
      });
      api.init();
      
      export const getClient = api.getClient<PetStoreClient>
      

       

      Note: If we do not pass the withServer the client will try to call the API on the same origin as the app. This means that all API calls will be on localhost for this example, which we do not want.

       

    2. Using the Client: For using the client we can define a separate file named services.ts this way we can have the logic of our API calls separate.

       

          // services.ts
      import { getClient } from "./axios";
      
      export const getAvailablePets = async () => {
        try {
          const client = await getClient();
          const { data } = await client.findPetsByStatus({ status: "available" });
          return data;
        } catch (error) {
          console.error(error);
        }
      };
      

       

      Now if we check the types of the findPetsByStatus method or the response data we can see that everything is typed and easy to use.

       

      Tips and Tricks for Optimal Use

      Leveraging openapi-client-axiosand type generation can be highly beneficial. Here are some tips to maximize their effectiveness:

      1. Automate Type Generation: Integrate the type generation command into your build process or set it up as a pre-commit hook to ensure your types are always up to date.
      2. Customize Client Instances: Use interceptors to add custom headers, and authentication tokens, or handle errors globally.
      3. Modularization: Group related API operations and types into modules, making them easier to manage and import. you can have a separate folder named API in which we can separate our services by the controller under which those are. An example architecture could look something like this:
      4.  

            - src
        	...
        	- api
        		...
        		users
        			- getUserById.ts
        			- getAllUsers.ts
        			...
        		...
        		axios.ts
        

         

      5. Keep an Eye on Performance: If your API specification is large, consider splitting the type generation to avoid bloating your project with unused types. This means that we can split the openapi.json into users-api.json, pets-api.json, and so on. Then we can generate the types from each of the above.
      6. Version Control: When you update your API specification, maintain versioned openapi.json files to support backward compatibility during the transition period.
      7.  

        By leveraging the power of OpenAPI generators and type generation, we can simplify and enhance our communication and development processes, making it easier to work with APIs and deliver high-quality software solutions.

        If you have any further questions or need assistance with OpenAPI generators, feel free to reach out. Happy coding!

Let’s start building!

You’re one step closer to making your idea a reality.