Configuration
EzBackend is designed from the bottom up to be extremely customisable, so that you can customise everything.
Overview
By default, running EzBackend looks like this
const app = new EzBackend();
app.start();
However, under the hood this comes with a default configuration. A general gist of the configuration is:
const app = new EzBackend();
app.start({
backend: {
listen: listenOpts,
fastify: fastifyOpts,
typeorm: typeormOpts,
},
cors: corsOpts,
auth: {
...authOpts
fastifySecureSession: fastifySecureSessionOpts,
google: googleOpts,
},
openAPI: openAPIopts
});
Understanding the config
Environment Loading
info
By default, EzBackend reads values from .env
in your root folder. There is no need to use dotenv.config()
, but do take note that the .env
is loaded by default.
Configuration Merging
When a configuration is passed to app.start()
, it is merged with the default declaration.
Example:
app.start({
backend: {
listen: {
port: 3000,
},
},
});
//Will be merged to become
app.start({
listen: {
port: 3000,
address: process.env.ADDRESS || '127.0.0.1',
},
...otherDefaultOpts,
});
Configuration Naming Convention
The convention for ezbackend plugins is to remove the Ez
in front of the plugin name and camelCase
it for the plugin options
Example:
//To configure the EzAuth Plugin
app.start({
auth: authOpts,
});
Configuration Overriding
By default, the configuration passed to app.start({...config})
is taken as the source of truth. Any values passed to app.start
will override the defaults.
Reference
backend
The configuration here is passed to fastify and typeorm. Further broken down into listen
fastify
and typeorm
backend.fastify
The arguments passed to fastify during instantiation. See the fastify docs for the full reference
Example:
app.start({
backend: {
fastify: {
logger: true, //Enable logging
ignoreTrailingSlash: true, //Ignore trailing slashes on HTTP Endpoints
},
},
});
backend.typeorm
The arguments passed to createConnection
from typeorm
during instantiation. See the typeorm docs for the full reference
warning
EzBackend automatically populates the entities field whenever a new EzModel is made. Avoid adding entities manually.
Example:
app.start({
backend: {
typeorm: {
host: "localhost",
port: 3306,
username: "test",
password: "test",
database: "test",
logging: true,
synchronize: true,
type: "postgres"
subscribers: [
"subscriber/*.ts"
],
migrations: [
"migration/*.js"
],
}
}
})
backend.listen
The arguments passed to fastify.listen
when the server is started.
Example:
app.start({
backend: {
listen: {
port: 80, //Listen on port 80
address: '0.0.0.0', //Listen on all IPv4 addresses
backlog: 500, //Maximum number of pending connections
},
},
});
backend.storage
The storage options consist of:
multipartOpts
- The options passed toFastifyMultipart
. These options will be used globallyengine
- The storage engine used globally (by default). See Custom Engines for more details
Example:
await app.start({
backend: {
storage: {
multipartOpts: {
limits: {
fileSize: 1024,
},
},
},
},
});
Storage can also be configured at the Router Level. See file storage for more details
cors
The arguments passed to fastify-cors
to configure cors. See the fastify-cors docs for the full reference
warning
credentials:true
is a requirement for EzAuth to work, unless your frontend is hosted the same EzBackend instance
Example:
app.start({
cors: {
origin: (origin, cb) => {
if (/localhost/.test(origin)) {
// Request from localhost will pass
cb(null, true);
return;
}
// Generate an error on other origins, disabling access
cb(new Error('Not allowed'));
},
},
});
info
To resolve the warning ⚠️ Reflecting the cors origin leaves your backend vulnerable to CSRF attacks. Set it only to trusted urls.
You need to set the origin
property to an array of hosts from which your frontend is hosted.
e.g. If your frontend is on xyz.ggbet.com
app.start({
cors: {
origin: ['xyz.ggbet.com'],
},
});
auth
The options passed to EzAuth
, a subset of which is passed to fastifySecureSession
The default options for auth should be sufficient for most use cases, and it is best to configure it through the environment.
For example
SECRET_KEY=my-super-secret-key-that-no-one-will-guess
AUTH_SUCCESS_REDIRECT=http://my-frontend.com/login/success
AUTH_FAILURE_REDIRECT=http://my-frontend.com/login/fail
GOOGLE_CLIENT_ID=xxx.apps.googleusercontent.com
GOOGLE_CLIENT_SECRET=yyy-zzz_aaa
However if you wish to further customise it, you can use the below sample or part thereof:
Full Sample:
app.start({
auth: {
//NOTE: ONLY DEFINE EITHER secretKey or secretKeyPath but NOT BOTH
secretKey: 'my-super-secret-key-that-no-one-will-guess',
secretKeyPath: './my-secret.key',
successRedirectURL: 'http://my-frontend.com/login/success',
failureRedirectURL: 'http://my-frontend.com/login/fail',
fastifySecureSession: fastifySecureSessionOpts,
google: {
googleClientId: 'xxx.apps.googleusercontent.com',
googleClientSecret: 'yyy-zzz_aaa',
scope: ['google'],
},
},
});
The fastify secure session opts are passed to fastify-secure session. See the fastify-secure-session docs for more info.
warning
For fastifySecureSessionOpts, for the cookie options the recommended configuration for your frontend to on a seperate URL is:
cookie: {
path: '/',
sameSite: 'none',
secure: true,
httpOnly: true
}
info
EzBackend uses fastify-passport under the hood. The options set for fastifySecureSession will also affect the functionality of fastify-passport
openAPI
The arguments passed to fastify-swagger
to configure openAPI. See the fastify-swagger docs for the full reference
warning
The routePrefix must be /docs
for EzDBUI
to work
Full example:
app.start({
openAPI: {
prefix: '/docs',
routePrefix: '/docs',
exposeRoute: true,
logLevel: 'warn',
openapi: {
info: {
title: 'EzBackend API',
description: 'Automatically generated documentation for EzBackend',
version: '1.0.0',
},
externalDocs: {
url: 'https://github.com/kapydev/ezbackend',
description: 'Find more info here',
},
},
},
});
Full Default Configuration Reference
const app = new EzBackend();
app.start({
backend: {
listen: {
port: process.env.PORT || 8000,
address: process.env.ADDRESS || '127.0.0.1',
},
fastify: {
logger: {
prettyPrint: {
translateTime: 'SYS:HH:MM:ss',
ignore: 'pid,hostname,reqId,responseTime,req,res',
messageFormat: (log, messageKey, levelLabel) => {
const method = log.req?.method;
const url = log.req?.url;
const status = log.res?.statusCode;
const resTime = log.responseTime?.toFixed(2);
const msg = log[messageKey];
if (method && url) {
return `${`[${method} ${url}`.padEnd(25, '.')}] ${msg}`;
}
if (status && resTime) {
return `${`[${status} ${resTime}ms`.padEnd(25, '.')}] ${msg}`;
}
return msg;
},
},
},
},
typeorm: {
type: 'better-sqlite3',
database: 'tmp/db.sqlite',
synchronize: true,
},
},
cors: {
origin: true,
credentials: true,
methods: ['GET', 'PUT', 'POST', 'PATCH', 'DELETE', 'OPTIONS'],
},
auth: {
secretKey: process.env.SECRET_KEY ?? undefined,
secretKeyPath: path.join(process.cwd(), 'secret-key'),
successRedirectURL: 'http://localhost:8000/db-ui',
failureRedirectURL: 'http://localhost:8000/db-ui',
fastifySecureSession: {
cookie: {
path: '/',
sameSite: 'none',
secure: true,
},
},
google: {
googleClientId: process.env.GOOGLE_CLIENT_ID!,
googleClientSecret: process.env.GOOGLE_CLIENT_SECRET!,
scope: ['google'],
},
},
openAPI: {
prefix: '/docs',
routePrefix: '/docs',
exposeRoute: true,
logLevel: 'warn',
openapi: {
info: {
title: 'EzBackend API',
description: 'Automatically generated documentation for EzBackend',
version: '1.0.0',
},
externalDocs: {
url: 'https://github.com/kapydev/ezbackend',
description: 'Find more info here',
},
},
},
});