Next.js + Redoc to create a low-latency API references
Tags: nextjs, react, redoc, openapi
Published: 2023-10-28 05:56:19

I'm currently developing an open-source headless CMS called Collections. During this project, the need arose for a public API specification, and we decided to try out the combination of Next.js (Nextra) and Redoc, which turned out to be quite effective. We've documented the procedure for your reference.

API specifications, like those using OpenAPI (Swagger), are typically created for each project, but sharing them with the public may not happen very often. Nonetheless, this is a domain where technology trends evolve relatively slowly, so it's worth keeping in mind!

## Completed product

![api](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ejffocfwfx8mcmlt0ikr.png)

The published page is [here](https://collections.dev/reference/api)

All code is available on GitHub for your reference.
https://github.com/collectionscms/collections/blob/main/docs/pages/reference/api.en.mdx

## What is Redoc?
This tool takes YAML files defined in the OpenAPI specification and transforms them into static documents in HTML format. It's an open-source tool.

In the case of Collections, we employ Nextra, a Next.js-based static site generator, to produce the complete document, which is subsequently integrated and rendered.

## Install Redoc as a component of React
Let's get started and follow the [official steps](https://redocly.com/docs/redoc/deployment/react/). First, install `@redocly/cli` and its associated dependencies.

```
npm i react react-dom mobx styled-components core-js
```

## Prepare yaml file
Next, create a yaml file based on the OpenAPI specification.
The Collections API specification is attached for your reference.

https://github.com/collectionscms/collections/blob/main/docs/data/api.yaml

If you are using VSCode, you should install the `OpenAPI (Swagger) Editor`, which will warn you of syntax errors so that you can proceed with your work quickly.

https://marketplace.visualstudio.com/items?itemName=42Crunch.vscode-openapi

## Add to component
When the file is ready, fill the page with Redoc components and it will automatically generate and output HTML!

```
import { RedocStandalone } from 'redoc';

<RedocStandalone specUrl="url/to/your/spec"/>
```

However, it is not possible to **reference local files** in the `specUrl`. This has been exchanged on GitHub issues, but is due to the same-origin policy and security reasons.
https://github.com/Redocly/redoc/issues/149#issuecomment-359285569

One option is to save yaml to S3, but this is more work, and I don't want to add a CI job to upload the files.

## Distribute via Next.js API and convert to SSG
Therefore, we solved this problem by using the Next.js API to respond to yaml and passing it on.

```
export default function handler(_req: NextApiRequest, res: NextApiResponse<ResponseData>) {
  const fullPath = path.join(dataDirectory, 'api.yaml');
  const fileContents = fs.readFileSync(fullPath, 'utf8');
  res.status(200).json(YAML.parse(fileContents));
}
```

Well, this would have been fine, but the rendering is quite slow due to each request, so we need to do something more. Redoc also has a property called `spec` that passes an object instead of a URL.

```
export const getStaticProps = ({ params }) => {
  return fetch(`https://collections.dev/api/openapi`)
    .then((res) => res.json())
    .then((repo) => ({
      props: {
        ssg: repo,
      },
    }));
};

export const Redoc = () => {
  const data = useData();
  return <RedocStandalone spec={data} />;
};
```

By pre-rendering and passing the object in SSG in this way, the response surface was successfully cleared!

## Performance

```
$ curl 'https://collections.dev/reference/api/' -H 'Accept-Encoding: gzip, deflate, sdch' -H 'Accept-Language: en-US,en;q=0.8,ja;q=0.6' -H 'Upgrade-Insecure-Requests: 1' -H 'User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.86 Safari/537.36' -H 'Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8' -H 'Connection: keep-alive' --compressed -o /dev/null -w  "%{time_starttransfer}\n" -s

0.239587
0.249859
0.255718
0.249946
0.253883
```
The response time is usually within 300 ms.

![api](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/g936ugoco8yxjt8ktnia.png)

`First Contentful Paint` is also 0.6sec. I think we can give it a passing grade since it is not a page that requires any further improvement or SEO.

## Finally
I'm building an open source headless CMS [Collections](https://collections.dev/) that turns WordPress into an API 🚀

It has Markdown (with GFM), dark mode, and other features that make it comfortable to write with. We also have a [Live Demo](https://demo.collections.dev), so please feel free to try it 🙌🙌

See you soon!