DEV Community

Cover image for Next.js + Redoc to create a low-latency API references
Kazane Shimizu for Collections

Posted on

Next.js + Redoc to create a low-latency API references

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

The published page is here

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. First, install @redocly/cli and its associated dependencies.

npm i react react-dom mobx styled-components core-js
Enter fullscreen mode Exit fullscreen mode

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"/>
Enter fullscreen mode Exit fullscreen mode

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));
}
Enter fullscreen mode Exit fullscreen mode

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} />;
};
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

The response time is usually within 300 ms.

api

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 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, so please feel free to try it 🙌🙌

See you soon!

Top comments (0)