Static segment
npx vovk new segment openapi --static # will create a new static segment with name "openapi" at src/app/api/openapi/[[...vovk]]/route.ts
Next.js is able to render API endpoints at build time using generateStaticParams . Vovk.ts provides generateStaticAPI
function to utilize this feature and generate static API endpoints for the lowest latency possible. You can use it to serve OpenAPI data, historical data (you can configure CI/CD job to be run periodically to update it), or any other static data that doesn’t change often. It can also be used in a Static Export mode with the output: 'export'
Next.js config setting:
/** @type {import('next').NextConfig} */
const nextConfig = {
output: 'export',
};
module.exports = nextConfig;
The only thing you need to do is to implement generateStaticParams
that returns generateStaticAPI
with controller list.
// ...
export type Controllers = typeof controllers;
export function generateStaticParams() {
return generateStaticAPI(controllers);
}
export const { GET } = initSegment({ controllers });
In order to make it work on a static website hosting like Github Pages, you may need to define .json
extension in your endpoint definition to make it return proper HTTP headers.
import { get, prefix } from 'vovk';
@prefix('hello')
export default class HelloController {
@get('greeting.json')
static async getHello() {
return { greeting: 'Hello world!' };
}
}
As result you’re going to get an endpoint that looks like that: https://vovk.dev/api/hello/greeting.json (hosted on Github Pages).
In case if you use a custom slug (e.g. /src/app/api/[[...custom]]/route.ts
) instead of vovk
, the default value, you can provide it as a second argument.
export function generateStaticParams() {
return generateStaticAPI(controllers, 'custom');
}
Static endpoint params
@get
decorator accepts a set of options, one of them is staticParams
that allows to define static parameters for the endpoint to simulate conditional routing. The example below demonstrates a static API represented by a single handler that renders 6 sets of static parameters: section (a | b
) and page (1 | 2 | 3
).
import { z } from 'zod/v4';
import { prefix, get, operation } from 'vovk';
import { withZod } from 'vovk-zod';
@prefix('static-params')
export default class StaticParamsController {
@operation({
summary: 'Static Params',
description: 'Get the static params: section and page',
})
@get('{section}/page{page}.json', {
staticParams: [
{ section: 'a', page: '1' },
{ section: 'a', page: '2' },
{ section: 'a', page: '3' },
{ section: 'b', page: '1' },
{ section: 'b', page: '2' },
{ section: 'b', page: '3' },
],
})
static getStaticParams = withZod({
params: z.object({
section: z.enum(['a', 'b']),
page: z.enum(['1', '2', '3']),
}),
handle: async (_req, { section, page }) => {
return { section, page };
},
});
}
It will build 6 JSON files:
- /static-params/a/page1.json
- /static-params/a/page2.json
- /static-params/a/page3.json
- /static-params/b/page1.json
- /static-params/b/page2.json
- /static-params/b/page3.json
See live example here
RPC client
It doesn’t matter wether you use static API or dynamic one, you can use the same RPC client to call it. This includes client-side validation, type inference, etc.
const resp = await StaticParamsRPC.getStaticParams({
params: {
section: 'a',
page: '1',
},
});
console.log(resp); // { section: 'a', page: '1' }
Troubleshooting
Sometimes when output: 'export'
is set at the next.config.js
you may see the schema parsing error, when dev
command is run:
⨯ SyntaxError: Unexpected non-whitespace character after JSON at position 396 (line 1 column 397)
at JSON.parse (<anonymous>) {
page: '/api/_schema_'
}
In order to avoid this error, when npm run dev
is going to be run, close the browser tabs where the app is opened until the initial request to /_schema_
is finished. After that you can open the app in the browser again and it should work fine. If you still see the error, feel free open an issue at Vovk.ts GitHub repository with the details.