npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

kenai

v1.2.15

Published

Creation and management of Fastify routes using decorators.

Downloads

1,509

Readme

Table of content

Installation

npm install kenai

First steps

Before we start using the decorators, we need to configure Kenai as a Fastify plugin. Below are the plugin configuration options:

| Option | Description | Mandatory | | ---------------------- | ---------------------------------------------------------------------------------- | --------- | | routers | Used to define new routes from this endpoint | Yes | | zodCustomParser | Define a custom parser for Zod errors | No | | redis | Defines the Redis configuration for routes with cache | No | | controllerParameters | Defines the parameters for the controller class, such as the server itself | No | | bufferRedisData | Define if Redis data should be stored in a buffer, this helps to save memory space | No |

Example of how to configure the plugin:

import MainRouter from './routers/';
import { KenaiPlugin } from 'kenai';
import fastify from 'fastify';

const app = fastify({ ignoreTrailingSlash: true });

app.register(KenaiPlugin, { mainRoute: MainRouter });

app.listen({ port: 3000 }, (err, address) => {
    if (err) throw err;
    console.log(`Server listening at ${address}`);
});

Decorators

Router

This decorator is responsible for creating routes in Fastify, allowing you to define middlewares, new routes, and controllers in a single call.

External routes defined inside the decorator body are automatically integrated, dynamically associating their URLs with the 'child' routes and this also applies to middlewares.

Configuration options:

| Option | Description | Mandatory | | ------------- | ---------------------------------------------------------- | --------- | | routers | Used to define new routes from this endpoint | Yes | | middlewares | Responsible for adding middleware to routes for validation | No | | controllers | Responsible for adding controllers to routes | Yes |

Below is an example of how to create a route:

import { Router, Get } from 'kenai';

@Router('/hello-world')
export default class MainRouter {
    @Get()
    helloWorld() {
        return 'Hello World!';
    }
}

Creating external routes and controllers:

Controllers are defined using the Methods decorators

import { Router, Get } from 'kenai';

class HelloWorldController {
    @Get()
    helloWorld() {
        return 'Hello World!';
    }
}

// External route but interconnected, final url: /v1/hello-world
@Router('/hello-world', {
    controllers: [HelloWorldController]
});
class HelloWorldRouter {}

@Router('/v1', {
    routers: [HelloWorldRouter],
})
export default class MainRouter {}

Middlewares

The middlewares are responsible for validating the requests, being invoked before the main processing and executed afterwards.

Example of how to create a middleware:

You can add more than one middleware, just separate them with a comma.

function ContentTypeValidator(request, reply, done) {
    if (request.headers['Content-Type'] !== 'application/json')
        throw new Error('Não aceito esse tipo de conteúdo');

    return done();
}

@Router('/')
class MainRouter {
    @Middleware(ContentTypeValidator)
    @Get()
    helloWorld() {
        return 'Hello World!';
    }
}

BodySchema

This decorator is responsible for validating all data sent to the request body, using Zod as a validation schema.

| Option | Description | Required | | ----------------- | -------------------------------------------------------------------------------- | -------- | | schema | Defines the validation schema using zod | Yes | | omitUnknownKeys | Defines whether the validator should remove keys that do not exist in the schema | No |

Example of how to use BodySchema:

import { BodySchema, Post } from 'kenai';
import { z } from 'zod';

class MainRouter {
    @BodySchema(z.object({ name: z.string().min(1) }))
    @Post()
    run(request) {}
}

QuerySchema

This decorator is responsible for validating all data sent in the request URL, using Zod as a validation schema.

The schema created in zod must have all properties as optional, otherwise it will create errors for values that were not informed.

| Option | Description | Required | | ----------------- | -------------------------------------------------------------------------------- | -------- | | schema | Defines the validation schema using zod | Yes | | omitUnknownKeys | Defines whether the validator should remove keys that do not exist in the schema | No |

Example of how to use QuerySchema:

import { QuerySchema, Get } from 'kenai';
import { z } from 'zod';

class MainRouter {
    @QuerySchema(z.object({ name: z.string().min(1).optional() }))
    @Get()
    run(request) {}
}

ParamsSchema

This decorator is responsible for validating all parameters passed in the Url of the request, using the Zod as a validation schema.

| Option | Description | Required | | -------- | --------------------------------------- | -------- | | schema | Defines the validation schema using zod | Yes |

Example of how to use the ParamsSchema:

import { ParamsSchema, Get } from 'kenai';
import { z } from 'zod';

class MainRouter {
    @ParamsSchema(z.object({ name: z.string().min(1) }))
    @Get()
    run(request) {}
}

Returns

This decorator defines all possible returns of the request, defining the status and body of the response using Zod as validation for the output.

| Option | Description | Required | | -------- | --------------------------------------- | -------- | | status | Defines the status of the response | Yes | | schema | Defines the validation schema using zod | No |

Example of how to use Returns:

import { Returns, Get } from 'kenai';
import { z } from 'zod';

class MainRouter {
    @Returns(200, z.object({ name: z.string().min(1) }))
    @Returns(201)
    @Get()
    run() {
        return { name: 'Kenai' };
    }
}

Methods

The methods are responsible for creating the route controllers.

All methods accept the same parameters:

| Option | Description | Required | | --------------------- | ------------------------------------------------------------------------------------------------- | -------- | | path | Defines the route path | Yes | | fastifyRouteOptions | Defines Fastify route options | No |

Get

This decorator is responsible for creating a controller for a GET route.

Example of how to use Get:

import { Get } from 'kenai';

class MainRouter {
    @Get('/hello-world')
    helloWorld() {
        return 'Hello World!';
    }
}

Post

This decorator is responsible for creating a controller for a POST route.

Example of how to use Post:

import { Post } from 'kenai';

class MainRouter {
    @Post('/hello-world')
    helloWorld() {
        return 'Hello World!';
    }
}

Put

This decorator is responsible for creating a controller for a PUT route.

Example of how to use Put:

import { Put } from 'kenai';

class MainRouter {
    @Put('/hello-world')
    helloWorld() {
        return 'Hello World!';
    }
}

Patch

This decorator is responsible for creating a controller for a PATCH route.

Example of how to use Patch:

import { Patch } from 'kenai';

class MainRouter {
    @Patch('/hello-world')
    helloWorld() {
        return 'Hello World!';
    }
}

Delete

This decorator is responsible for creating a controller for a DELETE route.

Example of how to use Delete:

import { Delete } from 'kenai';

class MainRouter {
    @Delete('/hello-world')
    helloWorld() {
        return 'Hello World!';
    }
}

Params

The 'params' are responsible for creating custom parameters in the route handler.

All 'params' accept these same parameters:

| Option | Description | Mandatory | | ------ | ------------------------------------------------------ | --------- | | key | Name of some value that can be obtained in that object | Yes |

Reply

This decorator returns the entire response body.

Example of how to use Reply:

import { Reply, Post } from 'kenai';

class MainRouter {
    @Post('/hello-world')
    helloWorld(@Reply() reply: FastifyReply) {
        return reply.code(401).send('Unauthorized');
    }
}

// Getting values within the request body

class MainRouter {
    @Post('/hello-world')
    helloWorld(@Reply('statusCode') statusCode: number) {
        return statusCode;
    }
}

Request

This decorator returns the entire request object.

Example of how to use Request:

import { Request, Post } from 'kenai';

class MainRouter {
    @Post('/hello-world')
    helloWorld(@Request() request: FastifyRequest) {
        return request;
    }
}

// Getting values within the request body

class MainRouter {
    @Post('/hello-world')
    helloWorld(@Request('body') body: any) {
        return body;
    }
}

Params

This decorator returns all parameters of the request.

Example of how to use the Params:

import { Params, Post } from 'kenai';

class MainRouter {
    @Post('/hello-world/:name')
    helloWorld(@Params() params: Record<string, string>) {
        return params;
    }
}

Body

This decorator returns the entire request body.

Example of how to use Body:

import { Body, Post } from 'kenai';

class MainRouter {
    @Post('/hello-world')
    helloWorld(@Body() body: any) {
        return body;
    }
}

Query

This decorator returns all query parameters of the request.

Example of how to use the Query:

import { Query, Post } from 'kenai';

class MainRouter {
    @Post('/hello-world')
    helloWorld(@Query() query: Record<string, string>) {
        return query;
    }
}

Headers

This decorator returns all request headers.

Example of how to use the Headers:

import { Headers, Post } from 'kenai';

class MainRouter {
    @Post('/hello-world')
    helloWorld(@Headers() headers: Record<string, string>) {
        return headers;
    }
}

Cache

Cache

This decorator allows you to store the result of a route in cache. This means that, when a request is made to this route, the results are stored in the cache and reused in the next request, thus saving response time.

To enable the caching system, you must establish a connection with Redis in the Kenai configuration options (Plugin).

| Option | Description | Required | | ------ | ------------------------------------------------------- | -------- | | time | Time in seconds that the result will be stored in cache | Yes |

Example of how to use the Cache:

import { Cache, Get } from 'kenai';

class MainRouter {
    @Get('/hello-world')
    @Cache(60)
    helloWorld() {
        return 'Hello World!';
    }
}

Cache.InvalidateOnUpdate

This decorator allows you to invalidate the cache of a route whenever the stored content is updated. This means that, when calling the route, the corresponding cache will be automatically invalidated, ensuring that the next request returns updated data.

For example, I have a route that fetches all users from the database and another that updates a specific user. When I update a user, I want the cache to be invalidated so that I can have the updated data in the next request.

Example of how to use the Cache.InvalidateOnUpdate:

import { Cache, Get } from 'kenai';

class MainRouter {
    @Post('/hello-world')
    @Cache.InvalidateOnUpdate()
    helloWorld() {
        return 'Hello World!';
    }
}

OpenAPI

The decorators in this category are responsible for describing routes, automatically generating documentation with Swagger from these descriptions.

Decorators such as BodySchema, ParamsSchema, QuerySchema, and Returns accept Zod as a validation schema. This allows you to define detailed descriptions for values using the describe function, or create complete specifications with the zod-to-openapi package.

Description

This decorator defines a description about the route.

| Option | Description | Required | | ------------- | ------------------- | -------- | | description | Describes the route | Yes |

Example of how to use the Description:

import { Description, Get } from 'kenai';

class MainRouter {
    @Get('/hello-world')
    @Description('Hello World!')
    helloWorld() {
        return 'Hello World!';
    }
}

Summary

This decorator defines a summary about the route.

| Option | Description | Required | | --------- | ------------- | -------- | | summary | Route summary | Yes |

Example of how to use the Summary:

import { Summary, Get } from 'kenai';

class MainRouter {
    @Get('/hello-world')
    @Summary('Hello World!')
    helloWorld() {
        return 'Hello World!';
    }
}

Tags

This decorator defines tags for the route. Tags are very useful for organizing routes into logical categories, making the API documentation easier to understand and navigate.

| Option | Description | Required | | ------ | ----------- | -------- | | tags | Route tags | Yes |

Example of how to use the Tags:

import { Tags, Get } from 'kenai';

class MainRouter {
    @Get('/hello-world')
    @Tags('Hello World')
    helloWorld() {
        return 'Hello World!';
    }
}

Consumes

This decorator defines which types of content can be sent in the request. It is useful for specifying if the route only accepts application/json, for example.

| Option | Description | Required | | ---------- | ---------------------- | -------- | | consumes | Accepted content types | Yes |

Example of how to use the Consumes:

import { Consumes, Post } from 'kenai';

class MainRouter {
    @Post('/hello-world')
    @Consumes(['application/json'])
    helloWorld() {
        return 'Hello World!';
    }
}

Security

This decorator defines which securities should be used to protect the route. It is useful for specifying if the route needs authentication, for example.

| Option | Description | Required | | ---------- | ---------------- | -------- | | security | Route securities | Yes |

Example of how to use the Security:

import { Security, Post } from 'kenai';

class MainRouter {
    @Post('/hello-world')
    @Security({ apiKey: [] })
    helloWorld() {
        return 'Hello World!';
    }
}

OperationId

This decorator defines the name of an operation. It is useful for defining different names for operations in the same controller.

| Option | Description | Required | | ------------- | -------------- | -------- | | operationId | Operation name | Yes |

Example of how to use the OperationId:

import { OperationId, Get } from 'kenai';

class MainRouter {
    @Get('/hello-world')
    @OperationId('helloWorld')
    helloWorld() {
        return 'Hello World!';
    }
}

Deprecated

This decorator defines if the route is deprecated. It is useful for marking routes that should not be used in production.

Example of how to use the Deprecated:

import { Deprecated, Get } from 'kenai';

class MainRouter {
    @Get('/hello-world')
    @Deprecated
    helloWorld() {
        return 'Hello World!';
    }
}

Hide

This decorator defines if the route should be hidden. It is useful for marking routes that should not be displayed in the API documentation.

Example of how to use the Hide:

import { Hide, Get } from 'kenai';

class MainRouter {
    @Get('/hello-world')
    @Hide
    helloWorld() {
        return 'Hello World!';
    }
}

Extra

createParamsDecorator

Use this function to create decorators for route parameters. For example:

| Option | Description | Required | | ------ | ------------------------------------------------- | -------- | | path | Initial path where the parameter will be obtained | Yes | | key | Property name that you want to obtain | No |

import { createParamsDecorator, Get } from 'kenai';

const Session = (key?: string) => createParamsDecorator('request/session', key);
// Or
const IP = createParamsDecorator('request/ip');

export class MainRouter {
    @Get('/')
    run(@Session() session: any, @IP ip: string) {
        return { session, ip };
    }
}