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 the segment is to return generateStaticAPI
results from generateStaticParams
function.
// ...
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, openapi } from 'vovk';
import { withZod } from 'vovk-zod';
@prefix('static-params')
export default class StaticParamsController {
@openapi({
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 }; // return the params as is
},
});
}
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' }