NestJs Features
We have implemented configurable features to make using the NestJs component of Skulljs as easy as possible.
NestJs Documentation
For more information check out the official documentation.
Official NestJs Documentation ā
Global Configuration
The configuration for the global features can be found in the file detailed below.
// backend/src/configs/configuration.ts
export const configuration = () => ({
// Api
production: false,
// general prefix for nestjs routes
apiPrefix: "api",
// nestjs port
port: 3000,
// Access Logger
// the max size of the file before it rotates
accessLoggerFileSize: "10M",
// the max time before it rotates
accessLoggerFileInterval: "1d",
// Helmet
// false for sk build
helmetContentSecurityPolicy: false,
// Cors
// allowed origins | Ex: angular
corsOrigins: ["http://localhost:4200"],
// OpenApi
// path of the open api docs
openAPIPath: "api",
// title of the open api docs
openAPITitle: "skulljs nestjs example",
// description of the open api docs
openAPIDescription: "nestjs component for skulljs",
// version of the open api docs
openAPIVersion: "1.0",
// Session
// ! you need to change this
sessionSecret: "changeMeOrInsecure",
// value in ms | 1 day
sessionCookieMaxAge: 86400000,
// true = Forces the session to be saved back to the session store, even if the session was never modified during the request.
sessionResave: false,
// true = Forces a session that is "uninitialized" to be saved to the store. A session is uninitialized when it is new but not modified.
sessionSaveUninitialized: false,
// Specifies the boolean value for the HttpOnly Set-Cookie attribute.
sessionCookieHttpOnly: false,
// Specifies the boolean value for the Secure Set-Cookie attribute.
sessionCookieSecure: "auto",
// Mailer
// Smtp Host
mailerSmtpHost: "smtp.example.com",
// Smtp Port
mailerSmtpPort: 25,
// Default from for mails
mailerDefaultFrom: '"skulljs" <skulljs@example.com>',
// Email address for mail diversion in dev env
mailerDevEnvRedirectEmail: 'redirect@example.com',
// Crypto
// ! you need to change this, === 32 characters
cryptoSecretKey: "changeMeOrInsecure".padEnd(32, "!"),
// ! you need to change this
cryptoHashSaltString: 'changeMeOrInsecure',
});
ORM: Prisma
We have selected Prisma as the ORM for the NestJs component of Skulljs.
Why Prisma?
- Easy to Use: Prisma is designed to be easy to use. Its declarative syntax makes it easy to read and understand the code, even for developers who are not familiar with the underlying database technology.
- Performance: Prisma is optimized for performance, with features like query batching and automatic query optimization that can significantly reduce the number of database requests and improve response times. Prisma also uses modern database connectors like PostgreSQL and MySQL to ensure that data is retrieved and processed as quickly as possible.
- Flexibility: Prisma is highly flexible and can be used with a wide range of databases and technologies. It supports multiple databases, including MySQL, PostgreSQL, and SQLite.
- Strong Type Safety: Prisma provides strong type safety by generating TypeScript types for your database schema. This helps to catch errors early and ensures that your code is more robust and reliable.
- Open-Source: Prisma is an open-source project that is actively maintained by a community of developers. This means that it is free to use and can be customized and extended to meet your specific needs.
For more information check out the official documentation.
Official Prisma Documentation ā
Schema
The database schema can be found in the file detailed below.
// backend/prisma/schema.prisma
generator client {
provider = "prisma-client-js"
}
datasource db {
provider = "mysql"
url = env("DATABASE_URL")
}
model Cats {
id Int @id @default(autoincrement())
name String
color String
weight String
eyes_color String
}
Seeder
The seeder can be found in the file detailed below.
// backend/prisma/seed.ts
import { faker } from '@faker-js/faker';
import { PrismaClient, Cats } from '@prisma/client';
const prisma = new PrismaClient();
async function main() {
const data: Cats[] = [];
for (let i = 1; i <= 50; i++) {
data.push({ id: i, name: faker.animal.cat(), color: faker.color.human(), weight: faker.number.int().toString(), eyes_color: faker.color.human() });
}
const cats = await prisma.cats.createMany({ data, skipDuplicates: true });
console.log({ cats });
}
main().catch(async (err) => {
console.log(err);
await prisma.$disconnect();
process.exit(1);
});
Usage
We have created a service to facilitate NestJs integration. Here are the instructions on how to use it.
// any route module
import { PrismaService } from "src/prisma.service";
@Module({
controllers: [CatsController],
providers: [CatsService, PrismaService],
})
export class CatsModule {}
// any route service
import { PrismaService } from "src/prisma.service";
@Injectable()
export class CatsService {
constructor(private readonly prisma: PrismaService) {}
findAll() {
return this.prisma.cats.findMany();
}
}
Session
Skulljs’s NestJs component comes with a built-in session manager.
Session settings
The session’s settings can be found in the file detailed below.
// backend/src/configs/configuration.ts
export const configuration = () => ({
// Session
// ! you need to change this
sessionSecret: "changeMeOrInsecure",
// value in ms | 1 day
sessionCookieMaxAge: 86400000,
// true = Forces the session to be saved back to the session store, even if the session was never modified during the request.
sessionResave: false,
// true = Forces a session that is "uninitialized" to be saved to the store. A session is uninitialized when it is new but not modified.
sessionSaveUninitialized: false,
// Specifies the boolean value for the HttpOnly Set-Cookie attribute.
sessionCookieHttpOnly: false,
// Specifies the boolean value for the Secure Set-Cookie attribute.
sessionCookieSecure: "auto",
});
Session type
The description of the session type can be found in the file detailed below.
// backend/src/types/session.d.ts
import "express-session";
declare module 'express-session' {
interface Session {
user?: {
isLogged: boolean;
role: Roles;
// Declare here your session data
};
}
}
Usage
// any route controller or service
import { ..., Session } from '@nestjs/common';
import { Session as SessionExpress } from 'express-session';
@Controller('cats')
export class CatsController {
...
@Get('admin')
admin(@Session() session: SessionExpress) {
return this.catsService.admin(session);
}
}
IsAuthorized Guard
To simplify access management of NestJs routes, Skulljs comes equipped with a built-in guard named IsAuthorized
.
The guard comes with two modes:
- Minimun Role Mode: check if the user have the listed role or a superior one
- List Role Mode: check if the user have one of the listed roles
You can switch the mode with the minimunRoleMode boolean.
Roles description
You can add or remove any roles in the file detailed below.
// backend/src/guards/is-authorized/roles.ts
export enum Roles {
NonLoggedUser = 0,
LoggedUser = 10,
Admin = 80,
// Example
MyRole = 20,
}
Usage
// any route controller
import { Authorize } from 'src/decorators/authorize.decorator';
import { Roles } from 'src/guards/is-authorized/roles';
@Controller('cats')
export class CatsController {
...
@Get('admin')
@Authorize([Roles.MyRole], {minimunRoleMode: true})
admin() {
return this.catsService.admin();
}
}
Mailer
Skulljs’s NestJs component comes with a build-in mailer.
The mailer redirect all mail to the mailerDevEnvRedirectEmail defined in config while the app is in dev env.
Mailer settings
The mailer settings can be found in the file detailed below.
// backend/src/configs/configuration.ts
export const configuration = () => ({
// Mailer
// Smtp Host
mailerSmtpHost: "smtp.example.com",
// Smtp Port
mailerSmtpPort: 25,
// Default from for mails
mailerDefaultFrom: '"skulljs" <skulljs@example.com>',
// Email address for mail diversion in dev env
mailerDevEnvRedirectEmail: 'redirect@example.com',
});
Mailer usage
// any route service
import { MailerService } from '@nestjs-modules/mailer';
import * as Utils from '../../utils/utils';
@Injectable()
export class CatsService {
constructor(private readonly mailerService: MailerService, ...) {}
...
sendMail() {
Utils.sendMail(this.mailerService, {
to: 'user.name@example.com', // list of receivers
subject: '[skulljs] The cats have been created ā', // Subject line
template: 'cats',
context: {
// Data to be sent to template engine.
name: 'john doe',
},
});
}
}
Utils
Skulljs’s Nestjs component comes with built-in utils.
Array.prototype.asyncForEach
Asynchronous forEach
const data = [];
const cats = await this.prisma.cats.findMany();
await cats.asyncForEach(async (cat) => {
const food = await this.prisma.foods.findUnique({ where: { id: cat.food_id } });
data.push({ cat, food });
});
Array.prototype.shuffle
Function to shuffle an array
const cats = await this.prisma.cats.findMany();
const cats_shuffle = cats.shuffle();
TemplateToPDF
PDF generation from Handlebars template
// any route service
import * as Utils from '../../utils/utils';
@Injectable()
export class CatsService {
...
async printPDFFromTemplate(id: number): Promise<Buffer> {
const cat = await this.prisma.cats.findUnique({ where: { id } });
return Utils.templateToPDF({ template: 'cats', context: { cat } });
}
}
PDFGenerator
PDF generation from class
// any route service
import * as Utils from '../../utils/utils';
@Injectable()
export class CatsService {
...
async printPDFFromClass(id: number): Promise<Buffer> {
const cat = await this.prisma.cats.findUnique({ where: { id } });
const pdf = new Utils.PDFGenerator()
.createDocument()
.addNewPageListener()
.newPage()
.writeTitle('Export Cat')
.writeSubtitle(`Cat NĀ°${cat.id}`)
.writeLabelValuePair('name', cat.name, 200)
.writeLabelValuePair('weight', cat.weight, 200)
.writeLabelValuePair('color', cat.color, 200)
.writeLabelValuePair('eyes_color', cat.eyes_color, 200);
return pdf.closeAndGetBytes();
}
}
Encrypt, Decrypt and Hash
Functions for encrypt, decrypt and hash
// any route service
import * as Utils from '../../utils/utils';
@Injectable()
export class CatsService {
...
async crypto() {
const rawData = 'iAmATestString';
const encryptedData = Utils.crypto.encrypt(rawData);
return { rawData: Utils.crypto.decrypt(encryptedData), encryptedData: encryptedData, hash: await Utils.crypto.hash(rawData) };
}
}
Open API
For the API documentation Skulljs uses Open API. The default URL for Open API documentation is http://localhost:3000/api.
Open API settings
The Open API settings can be found in the file detailed below.
// backend/src/configs/configuration.ts
export const configuration = () => ({
// OpenAPI
// path of the open api docs
openAPIPath: "api",
// title of the open api docs
openAPITitle: "skulljs nestjs example",
// description of the open api docs
openAPIDescription: "nestjs component for skulljs",
// version of the open api docs
openAPIVersion: "1.0",
});
Usage
// any route controller
import { ApiTags, ApiOkResponse } from '@nestjs/swagger';
import { Cat } from './entities/cat.entity';
@ApiTags('cats')
@Controller('cats')
export class CatsController {
...
@Get()
@ApiOkResponse({ type: Cat })
findAll() {
return this.catsService.findAll();
}
}