@tmlmobilidade/connectors
Version:
This package provides pre-made database connectors to streamline development and reduce boilerplate. By using these connectors, you can avoid re-implementing controller classes every time, ensuring consistency and saving development time.
154 lines (153 loc) • 5.55 kB
JavaScript
/* * */
import '@fastify/cookie';
import '@fastify/cors';
/* * */
import cookie from '@fastify/cookie';
import cors from '@fastify/cors';
import { HttpException, HttpStatus } from '@tmlmobilidade/lib';
/* * */
import fastify from 'fastify';
/**
* FastifyService is a singleton class that provides a Fastify server instance.
* It allows for setting up routes, plugins, and starting/stopping the server.
* This class is designed to be used as a service in a Node.js application.
* It uses the Fastify framework for building web applications and APIs.
*/
export class FastifyService {
//
static _instance;
server;
host;
origin;
port;
/**
* Creates an instance of FastifyService.
* @param options The options for the Fastify server.
*/
constructor(options) {
this.server = fastify(options);
this.origin = options.origin ?? true;
this.port = options.port ?? 5050;
this.host = options.host ?? '0.0.0.0';
this._setupDefaultRoutes();
this._setupPlugins();
}
/**
* Gets the singleton instance of FastifyService.
* @param options The options for the Fastify server.
* @return The singleton instance of FastifyService.
*/
static getInstance(options) {
if (!FastifyService._instance) {
// Create a new instance if it doesn't exist yet
FastifyService._instance = new FastifyService(options || {});
FastifyService._instance._setupHooks();
}
// Return the existing instance
return FastifyService._instance;
}
/**
* Starts the Fastify server.
* @return A promise that resolves to the URL of the Fastify server.
* @throws Will throw an error if the server fails to start.
*/
async start() {
try {
const serverUrl = await this.server.listen({ host: this.host, port: this.port });
this.server.log.info(`Server is running at ${serverUrl}`);
this.server.log.info(`CORS enabled for origin: ${this.origin}`);
this.server.log.info(`Listening on ${this.host}:${this.port}`);
return serverUrl;
}
catch (error) {
this.server.log.error({ error, message: 'Error starting server.' });
process.exit(1);
}
}
/**
* Stops the Fastify server.
* @return A promise that resolves when the server is stopped.
*/
async stop() {
try {
await this.server.close();
console.log('Fastify server stopped.');
}
catch (error) {
this.server.log.error(error);
process.exit(1);
}
}
/**
* Sets the URL of the Fastify server.
* @return The URL of the Fastify server.
*/
_setupDefaultRoutes() {
this.server.get('/', (req, res) => {
res.send('Jusi was here!');
});
}
/**
* Sets up hooks for the Fastify server including error handling and response processing.
*/
_setupHooks() {
/**
* Sets a global error handler for the Fastify server instance.
* This handler checks if the error is an instance of HttpException.
* If so, it sends a response with the appropriate status code and error message.
* This ensures consistent error responses for HTTP exceptions throughout the application.
*/
this.server.setErrorHandler((error, _, reply) => {
this.server.log.error(error);
if (error instanceof HttpException) {
reply.status(error.statusCode).send({
data: undefined,
error: error.message,
statusCode: error.statusCode,
});
}
else {
reply.status(HttpStatus.INTERNAL_SERVER_ERROR).send({
data: undefined,
error: 'Internal server error',
statusCode: HttpStatus.INTERNAL_SERVER_ERROR,
});
}
});
/**
* Adds an 'onSend' hook to the Fastify server instance.
* This hook intercepts every outgoing response before it is sent.
* It parses the payload as a JSON object (assuming it matches the HttpResponse<T> structure),
* and sets the HTTP status code of the reply to the value of 'statusCode' in the payload,
* defaulting to HttpStatus.OK if not present.
* This ensures that the HTTP status code in the response matches the statusCode property
* in the application's response payload, providing consistent status handling.
*/
this.server.addHook('onSend', (_, reply, payload, done) => {
try {
const payloadJson = JSON.parse(payload);
reply.code(payloadJson.statusCode ?? HttpStatus.OK);
}
// eslint-disable-next-line @typescript-eslint/no-unused-vars
catch (error) {
// Do nothing
}
finally {
done();
}
});
}
/**
* Sets up the plugins for the Fastify server.
* @return A promise that resolves when the plugins are set up.
*/
async _setupPlugins() {
//
await this.server.register(cors, {
credentials: true,
methods: ['GET', 'HEAD', 'POST', 'PUT', 'PATCH', 'OPTIONS'],
origin: this.origin,
});
await this.server.register(cookie);
}
}