test

Constatic

Discord Bot BaseAPI Servers

Fastify

The API server preset using Fastify comes pre-configured to simplify development. Here's what you need to know to get started:

Knowledge of the Fastify framework is essential for optimal use. Read the documentation: https://fastify.dev/

Entry Function

Just like in the project base we have the bootstrapApp function to load modules and start the bot, we also have the bootstrapServer function located in src/server/index.ts. This function is exported to be called as soon as the bot is ready:

src/index.ts
import { bootstrapApp } from "#base";
import { bootstrapServer } from "#server";
 
await bootstrapApp({ 
    workdir: import.meta.dirname,
    whenReady: bootstrapServer
});

With this setup, the Fastify server will start right after the bot goes online, receiving the Client as an argument.

Environment Variables

The Zod schema for environment validation is adjusted to allow new environment variables:

src/settings/env.ts
import { z } from "zod";
 
const envSchema = z.object({
    BOT_TOKEN: z.string({ description: "Discord Bot Token is required" }).min(1),
    WEBHOOK_LOGS_URL: z.string().url().optional(),
    SERVER_PORT: z.number({ coerce: true }).optional(), 
    // Env vars...
});
 
type EnvSchema = z.infer<typeof envSchema>;
 
export { envSchema, type EnvSchema };

This means you can change the PORT of the Fastify server by setting this variable in the .env file.

.env
BOT_TOKEN=yourtoken
SERVER_PORT=8080

Automatic Loading and Registration

By default, this preset comes with the @fastify/autoload plugin installed, allowing us to set up a folder with route handlers that are automatically defined:

src/server/index.ts
import fastify, { type FastifyInstance } from "fastify";
import autoload from "@fastify/autoload";
import type { Client } from "discord.js";
import path from "node:path";
// ...
 
export async function bootstrapServer(client: Client<true>){
    // ...
    app.register(autoload, { 
        dir: path.join(import.meta.dirname, "routes"), 
        routeParams: true, 
        options: client, 
    }); 
    // ...
}

This setup will import and register route handlers from all files in the src/server/routes folder.

Therefore, it is important that all files in the routes folder have a default export of a function that receives the Fastify instance, the Discord client, and the Fastify done function.

Here's an example of a root route returning some information:

src/server/routes/home.ts
import { defineRoutes } from "#server";
import { StatusCodes } from "http-status-codes";
 
export default defineRoutes((app, client) => {
    app.get("/", (_, res) => {
        return res.status(StatusCodes.OK).send({
            message: `🍃 Online on discord as ${client.user.username}`,
            guilds: client.guilds.cache.size,
            users: client.users.cache.size
        });
    });
});

The @fastify/autoload plugin imports subfolder modules and maps the path to a route.

Create a file in src/server/routes/users:

src/server/routes/users/route.ts
import { defineRoutes } from "#server";
import { StatusCodes } from "http-status-codes";
 
export default defineRoutes((app, client) => {
    app.get("/", (_, res) => {
        return res.status(StatusCodes.OK).send({
            message: "Retorna todos os usuários",
        });
    });
 
    app.get("/:id", (req, res) => {
        const { id } = req.params as { id: string };
 
        return res.status(StatusCodes.OK).send({
            message: "Retorna um usuário pelo id",
        });
    });
});

In the example above, two routes are registered: the first is /users, and the second is /users/:id.

Read the full documentation for the plugin to understand the best use cases: https://github.com/fastify/fastify-autoload

Cors

In this preset, the CORS plugin is already installed with a basic configuration:

src/server/index.ts
import fastify, { type FastifyInstance } from "fastify";
import cors from "@fastify/cors";
import type { Client } from "discord.js";
import path from "node:path";
// ...
 
export async function bootstrapServer(client: Client<true>){
    // ...
    app.register(cors, { origin: "*" }); 
    // ...
}

Read the full documentation for the plugin to understand the best use cases: https://github.com/fastify/fastify-cors

On this page