Routing

File-based Routing

The APIs are located in your /app/apidirectory.

It autoloads all the files that live in this directory if it follows the format below.

app/api/accounts/index.ts
export default async function Route (instance: FastifyInstance) {
    instance.get('/api/v1/account', handler);
    
    async function handler(request, reply) {
        console.log(request);
        reply.status(204);
    }
}

This file is automatically loaded when novel starts.

It still needs you to specify the endpoint of the API via Fastify's routing.

instanceis an instance of a Fastify plugin. All Fastify interfaces are available here and additional ones that are discussed below.

Below are all the examples of valid route registrations

instance.get('/api/v1/account', handler);
instance.post('/api/v1/account', handler);
instance.patch('/api/v1/account', handler);
instance.head('/api/v1/account', handler);
instance.put('/api/v1/account', handler);
instance.delete('/api/v1/account', handler);
instance.options('/api/v1/account', handler);
instance.any('/api/v1/account', handler);

// you can add fastify route options as well
instance.get('/api/v1/account', fastifyRouteOptions, handler);

The routes are attached in their own scope

Built-in Routes

Novel comes with plenty of built-in routes that are created to glue together various SaaS functionalities.

These routes are available under /app/api/internal/v1and exposed under /api/v1.

You can inspect these routes using the API reference in this documentation, or the files in the Novel API repository

See API Reference →

See https://github.com/madewithnovel/novel/tree/main/app/api/internal/v1

Protecting Routes

You can secure your endpoints by making use of the various ways Novel scopes requests. There are 2 standard modes: cookie and api keys.

The functions below are called Route Directives. Check other route directives available to you.

The cookie session allows all requests into the Novel API with the sessioncookie to be acknowledged and keep a session related to a user.

instance.authenticated()

You can access this session via the request variable in your handler.

app/api/accounts/index.ts
export default async function Route (instance: FastifyInstance) {
    instance.get('/api/v1/account', handler);
    instance.authenticated();
    
    async function handler(request, reply) {
        console.log(request.session);
        reply.status(204);
    }
}

These sessions are the same in both cookie and api key contexts.

There are also additional request variables available to you for convenience.

request.account

This includes details on which user is accessing that request.

request.account = {
    id: string,
    role: string,
    verified: boolean,
};

request.org

This includes details on which organization is being used by the current request

request.org = {
    id: string,
}

Request Context

Each route has access to a request context that uses Node's async_hooks, and @fastify/request-context library.

This allows Novel to tap into relevant context of the request outside of the request handler. For example, retrieving an account ID in a database model.

Using API Keys

If you want to restrict endpoints based on API keys, you can use the directive below:

instance.authorized()

app/api/accounts/index.ts
export default async function Route (instance: FastifyInstance) {
    instance.get('/api/v1/account', handler);
    instance.authorized();
    
    async function handler(request, reply) {
        console.log(request.session);
        reply.status(204);
    }
}

These sessions are the same in both cookie and api key contexts.

This will check if the API key belongs to a specific user and fill in the relevant session variables like the above.

You can use both authorized and authenticated directives in the same route definition.

Changelog

  • 2024-12-20 - Initial Documentation

Last updated

Was this helpful?