Getting Started

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.

/src/app/api/[[...vovk]]/route.ts
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.

/src/modules/hello/HelloController.ts
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.

/src/app/api/[[...vovk]]/route.ts
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

/src/modules/basic/BasicController.ts
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"
}