This package is still in development.
Nico is a modern backend framework build on koa, it's inspired by sails. Ultimately nico is an effort to provide a more clear way to build api services.
npm install @blastz/nico
import nico from '@blastz/nico';
// const nico = require('@blastz/nico').default
nico.init({
routes: {
'GET /users': {
controller: async (ctx) => {
return (ctx.body = []);
},
},
},
});
nico.start();
Nico use routes
config to register routes, the basic usage like:
nico.init({
routes: {
'GET /users': {
// ...
},
},
});
This will register a route whose path is /users
and http method is Get
.
Nesetd router also supported:
nico.init({
routes: {
'/api/v3': {
'/users': {
GET: {
// ...
},
POST: {
// ...
},
'/:id': {
DELETE: {
// ...
},
},
},
},
},
});
This config will register three routes
GET /api/v3/users
POST /api/v3/users
DELETE /api/v3/users/:id
By default, body parser only works when request method is POST
, PUT
or PATCH
, change it by parsedMethods
config.
You need to manually enable body parser on specific route, otherwise it won't work.
nico.init({
routes: {
'/api/v3': {
'/users': {
POST: {
bodyParser: true,
// ...
},
},
},
},
});
By default It will only parse json
and form
types.
To support multipart form data, you need to enable it.
nico.init({
//...
POST: {
bodyParser: {
multipartOpts: {
enable: true,
},
},
// ...
},
//...
});
You can pass formidable options directly in multipartOpts
like this:
nico.init({
//...
POST: {
bodyParser: {
multipartOpts: {
enable: true,
formidable: {
maxFileSize: 10 * 1024 * 1024,
},
},
},
// ...
},
//...
});
Same as multipart, you need to enable them by xmlOpts
and textOpts
configs.
Check more options in config types.
Use responses to change response format.
nico.init({
routes: {
'GET /users': {
controller: (ctx) => {
return ctx.ok([]); // { data: [], message: 'execute success', success: true }
},
},
},
responses: {
ok: function ok(data, message = 'execute success', success = true) {
this.status = 200;
this.body = {
success,
data,
message,
};
},
},
});
Nico support validate params
, query
, body
and files
, It's recommend to use it with Joi.
nico.init({
routes: {
'POST /users': {
controller: (ctx) => {
ctx.logger.info(ctx.state.body.name); // validated value will be mounted at ctx.state
},
bodyParser: true, // enable body parser middleware
validate: {
body: Joi.object({
username: Joi.string().trim().required().min(1).max(50),
}),
},
},
},
});
NOTE
Above validate will allow body
to be undefined
, use Joi.object().requried()
to block it.
Nico will throw validate error by default, the error will be cached by global error handler.
You can add onError
, onBodyParserError
, onValidateError
in responses
config to change default behavior.
nico.init({
responses: {
onError: function onError(err) {
this.status = 200;
return (this.body = {
message: err.message,
success: false,
});
}, // change global error handle
onBodyParserError: function onBodyParserError(err) {
this.status = 200;
return (this.body = {
message: err.message,
success: false,
});
}, // change body parser error handle
onValidateError: function onValidateError(err) {
this.status = 200;
return (this.body = {
message: err.message,
success: false,
});
}, // change validate error handle
},
});
Serve /assets
directory like this:
nico.init({
serve: {
root: path.resolve(process.cwd(), './assets'),
},
});
nico.init({
serve: {
root: path.resolve(process.cwd(), './assets'),
route: '/static',
},
});
Get /assets/avatar.png
by route {{serverUrl}}/static/avatar.png
.
Serve multiple directories also supported.
nico.init({
serve: [
{
root: path.resolve(process.cwd(), './assets'),
route: '/assets',
},
{
root: path.resolve(process.cwd(), './static'),
route: '/static',
},
],
});
Serve configs support koa-static options.
nico.init({
serve: {
opts, // from koa-static
},
});
nico has five log levels: fatal
, error
, warn
, info
, debug
and trace
.
Default console level is info
, file level is none
.
Check usage detail in @blastz/logger.
Change console level to trace:
import { logger, createConsoleTransport, LoggerLevel } from '@blastz/nico';
// Reset logger before nico init
logger.clear().add(createConsoleTransport({ level: LoggerLevel.Trace }));
nico.init({
// ...
});
Nico use appMiddlewares
and routeMiddlewares
to store middleware informations, app middlewares will execute when nico.init()
is called,
route middlewares will execute when http request come.
The default appMiddleware
is ['error-handler', 'not-found-handler', 'global-cors', 'responses', 'serve', 'routes']
.
The default routeMiddleware
is ['debug', 'controller-cors', 'csp', 'xframes', 'policies', 'body-parser', 'validate', 'controller']
.
Change default middlewares:
nico.appMiddlewares = [
InnerAppMiddleware.ERROR_HANDLER,
InnerAppMiddleware.GLOBAL_CORS,
InnerAppMiddleware.ROUTES,
];
nico.routeMiddlewares = [InnerRouteMiddleware.CONTROLLER];
Define custom middlewares:
nico.useAppMiddleware(async (ctx, next) => {
await next();
ctx.set('custom', 'custom');
});
nico.useRouteMiddleware(async (ctx, next) => {
await next();
ctx.set('custom', 'custom');
}, InnerRouteMiddleware.DEBUG);
nico.init();
The second argument is the middleware name, above example shows custom middleware will execute after debug
middleware.
Custom middleware will be added to the middlewares after use middleware function, the name in the middlewares is the name of the function.
The default second argument of useAppMiddleware
is global-cors
and useRouteMiddleware
is controller-cors
.
If the second argument is null
or not found in middlewares, the custom middleware will be execute before all middlewares.
Nico will handle SIGINT
and SIGTERM
by default, you can add custom signal handler like this:
nico.useSignalHandler('SIGINT', () => {
closeDB();
});
Nico will automatically await all requests end and close the server, you only need to add some side effects.
The process will force exit after 10 seconds, you can change it in nico.config.advancedConfigs.forceExitTime
.
Nico support cluster mode internal, use nico.startCluster(port: number, instances?: number)
to start nico with cluster mode.
The default instances will be cpu numbers.
- nico-build bundle project build on nico.
- nico-mongo (
⚠️ building) use mongo with nico. - nico-redis (
⚠️ building) use ioredis with nico.