Open API (Part 1): Generating API clients and documentation from an Open API spec

Open API (Part 1): Generating API clients and documentation from an Open API spec

Overview

This article starts a series of Open API-related blog posts.

OpenAPI, previously known as Swagger (a name still in use today for many of its tools), is a suite of tools that generate documentation and networking clients for various programming languages. It uses what’s called an Open API spec, which is versioned, and can be written in YAML and JSON (my preference being JSON).

The order of operations for these blog posts may be somewhat reversed, but in future posts I’ll get to how we can create these spec files in a couple of ways.

Options for generating documentation from an Open API spec YAML or JSON file

Generating documentation for an OpenAPI spec file is probably the easiest task out of all of these. There are many tools available for performing this operation, each with varying difficulties of time or money spent, here’s a few:

As you can see, there’s no shortage of options. There’s probably countless options I’ve missed, so feel free to mention them in the comments.

I got an email recently about the new feature for Hashnode’s documentation generator, and since I already use the platform for my blog and think very highly of it, I thought I’d give it a try.

It was very easy to create a docs site and point it to my OpenAPI spec. The hard part was creating that spec properly so that I liked what I saw on the generated API Reference.

For this, I decided to document the API for my portfolio website Tinacious Design. The OpenAPI spec can be viewed here.

You can take a look at the generated documentation here: https://tinacious-design-api.hashnode.space

Here it is in dark mode:

And in light mode:

Docs Summary

While the final product of this isn’t particularly useful for anyone except myself, I wanted to build out another proof-of-concept OpenAPI documentation approach. Another, you say? Yes, I’ve already tried out one method, and so I tried out another. More to come in future blog posts. This is only part 1 of a multiple part series.

Generating OpenAPI clients in TypeScript

One of the benefits of using OpenAPI is that since the spec follows a consistent and detailed format for an API, it can be used to generate API clients to avoid time spent writing out the code manually, which can be time-consuming and is prone to human error.

typescript-axios-generator

When I was working with GrowthBook I built them a CLI tool for generating type-safe feature flags and interfacing with the REST API. While there are countless options for JavaScript and TypeScript client generation with varying degrees of satisfaction, for this implementation, I ended up using the typescript-axios-generator. This tool generated API clients which I ended up wrapping using the repository pattern, which helped me quickly build out commands to support all of the REST API endpoints following a simple pattern.

hey-api/openapi-ts

For my own API that I documented using Hashnode’s new tool as shown above, I decided to try another solution and went with hey-api/openapi-ts.

First, I downloaded the OpenAPI script and then used their CLI tool to generate API clients using the spec.

curl https://tinaciousdesign.com/openapi.json > tmp/openapi.json
npx @hey-api/openapi-ts -i tmp/openapi.json -o src/api/client -c @hey-api/client-fetch

In the above script, I use curl to make a network request and send the output into a file at tmp/openapi.json, where tmp is a directory configured to be ignored by version control in my project.

After saving the spec to a file, I then run the openapi-ts CLI tool to generate a client and have it output to src/api/client which is the directory I’ve chosen for this task. Passing -c with a value configures which client we want to generate, in this case a networking client that uses the browser native fetch.

This generates multiple files, but the ones I care about most for my implementation are the services.gen.ts file and the supporting types.gen.ts file, which respectively contain the generated services I can use to call all the endpoints and supporting types.

For my proof-of-concept implementation, I decided to use React. The generator is framework-agnostic, so you can use any framework (or lack thereof) that you prefer. My implementation code looks like this:

// App.tsx

import { useEffect, useState } from "react";
import { portfolioGet } from "./api/services.gen";
import { PortfolioItem } from "./api/types.gen";
import "./styles.css";

export default function App() {
  const [isLoading, setIsLoading] = useState(false);
  const [items, setItems] = useState<PortfolioItem[]>([]);

  useEffect(() => {
    setIsLoading(true);

    portfolioGet()
      .then(({ data }) => {
        setItems(data.data);
      })
      .catch((err) => {
        // todo: handle error
      })
      .finally(() => {
        setIsLoading(false);
      });
  }, []);

  return (
    <>
      {/* View template-related code */}
    </>
  );
}

In order for this to work, I also needed to do some very minor bootstrapping in the index file, which requires setting the base URL for the client:

// index.tsx

import React from "react";
import ReactDOM from "react-dom/client";
import App from "./App";
import { client } from "./api/services.gen";

const rootElement = document.getElementById("root")!;
const root = ReactDOM.createRoot(rootElement);

// Initialize OpenAPI client
client.setConfig({
  baseUrl: "https://tinaciousdesign.com/api",
});

root.render(
  <React.StrictMode>
    <App />
  </React.StrictMode>
);

Arguably this OpenAPI client bootstrapping code could’ve gone elsewhere but putting it here makes the proof-of-concept quick to read.

The React proof-of-concept fetches all portfolio items and renders them in a 2-up to 4-up grid (depending on the screen size).

You can view this CodeSandbox here. The generated API files can be found in the api directory here.

API client-generation summary

We looked at how we can generate API clients in a couple of ways, and what example implementations could look like for 2 separate code generation approaches.

Summary

So that covers part 1 of this Open API series of blog tools. We went over how we can use an already-generated spec file to its full potential by generating documentation and API clients. Next, we’ll look at creating this spec file in 2 ways.

Stay tuned for more!