Getting Started
Quick install
Setup Vovk.ts with create-next-app (opens in a new tab).
npx create-next-app -e https://github.com/finom/vovk-hello-world
Inside the project folder run npm run dev
and open http://localhost:3000 (opens in a new tab).
Manual install
Create Next.js project with App Router
Follow this instruction (opens in a new tab) to install Next.js. Use TypeScript, App Router and src/
directory.
npx create-next-app
Choices example:
Install Vovk.ts and Concurrently
At the newly created folder run:
npm i vovk vovk-client
Then install concurrently (opens in a new tab), the recommended way to run Vovk.ts and Next.js together.
npm i concurrently --save-dev
Enable decorators
In your tsconfig.json set "experimentalDecorators"
to true
.
{
"compilerOptions": {
"experimentalDecorators": true,
// ...
}
}
Set up Next.js wildcard route handler and export types read by the client library
Create file /src/app/api/[[...vovk]]/route.ts where [[...vovk]] is a folder name indicating what Next.js documentation calls "Optional Catch-all Segment" (opens in a new tab) that can be customized. This is the core entry point for all Vovk.ts routes.
import { initVovk } from 'vovk';
export const runtime = 'edge';
const controllers = {};
const workers = {};
// export types used by the client
export type Controllers = typeof controllers;
export type Workers = typeof workers;
export const { GET, POST, PUT, DELETE } = initVovk({ controllers, workers });
Enabling Edge Runtime is optional.
Create first controller and add it to the controller object
Create HelloController.ts at /src/modules/hello/ with same-named static class.
import { get, prefix } from "vovk";
@prefix('hello') // prefix is optional
export default class HelloController {
@get('greeting')
static getHello() {
return { greeting: 'Hello world!' };
}
}
And add this class at /src/app/api/[[...vovk]]/route.ts to the controllers
object.
import HelloController from '../../../modules/hello/HelloController';
// ...
const controllers = { HelloController };
// ...
The code above creates GET endpoint to /api/hello/greeting
. You can also use named export for the controller if needed.
Run vovk dev
and next dev
with concurrently
Create an NPM script in package.json that runs vovk dev
and next dev
together specifying the port explicitly.
Vovk server also utilises the port by adding 6969 number to it (if Next.js PORT
is 3000, Vovk.ts port is 9969).
Vovk.ts works by exchanging data between Next.js and Vovk Server, which means knowing the ports on both sides is essential.
"scripts": {
"dev": "PORT=3000 concurrently 'vovk dev' 'next dev' --kill-others"
}
Once you run npx run dev
you're going to notice the new file .vovk.json created in the root of your project. This file contains required information to build the client and it needs to be committed.
It's going to be updated automatically when your project structure is changed. Open http://localhost:3000 (opens in a new tab).
Alternatively, you can use use built-in concurrently-like process runner to run both servers and assign ports automatically.
npx vovk dev --next-dev
Besides .vovk.json the command also generates client .js and .ts files inside node_modules/.vovk that are re-exported by vovk-client module to make no error if vovk-client is not installed. This approach is borrowed from Prisma ORM.
Create a React component
Now the client is generated you can safely import your client library from vovk-client.
'use client';
import { useState } from 'react';
import { HelloController } from 'vovk-client';
import type { VovkReturnType } from 'vovk';
export default function MyComponent() {
const [serverResponse, setServerResponse] = useState<VovkReturnType<typeof HelloController.getHello>>();
return (
<>
<button
onClick={async () => {
const response = await HelloController.getHello();
setServerResponse(response);
}}
>
Get Greeting from Server
</button>
<div>{serverResponse?.greeting}</div>
</>
);
}
Note that if you're using VSCode you're probably going to need to restart TS server (opens in a new tab) each time when you add a new controller or WPC class to your app because by the time being TS Server doesn't update types imported from node_modules automatically when they were changed. This is a well-known problem that bothers Prisma ORM developers for long time. In all other scenarios (when you add a new method, change body type, etc) you don't need to do that since TS server reads Controllers
and Workers
that you export from /src/app/api/[[...vovk]]/route.ts.
Next.js Server Components are also supported but require to define absolute URL (by default all requests are made to /api
). Check the Server Component Example (opens in a new tab) for more information.
The only argument of methods of the generated library has approximately the following signature:
interface Options extends Omit<RequestInit, 'body' | 'method'> {
reactNative?: { textStreaming: boolean };
prefix?: string;
disableClientValidation?: boolean;
body: VovkBody<typeof Controller.method>
params: VovkParams<typeof Controller.method>
query: VovkQuery<typeof Controller.method>
}
In other words it supports custom Next.js options (opens in a new tab) (because Next.js extends RequestInit
global type) as well as React Native Fetch API (opens in a new tab).
await HelloController.hello({
body: { foo: 'bar' },
next: { revalidate: 3600 },
});
Live Example
import { get, prefix } from 'vovk';
@prefix('basic')
export default class BasicController {
/**
* Return a greeting
*/
@get('greeting', { cors: true })
static getHello() {
return { greeting: 'Hello world!' };
}
}
Source code (opens in a new tab)
Build and deploy
You're going to need to run npx vovk generate
to generate the client before the build with the standard npx next build
or when node_modules are re-installed.
To easily build the project on Vercel you can create "vercel-build"
npm script at package.json.
"scripts": {
"vercel-build": "vovk generate && next build"
}