@blastz/nico v0.25.0
Nico 
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.
Installation
npm install @blastz/nicoHello 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();Router
Basic Router
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.
Nested Router
Nesetd router also supported:
nico.init({
  routes: {
    '/api/v3': {
      '/users': {
        GET: {
          // ...
        },
        POST: {
          // ...
        },
        '/:id': {
          DELETE: {
            // ...
          },
        },
      },
    },
  },
});This config will register three routes
GET /api/v3/usersPOST /api/v3/usersDELETE /api/v3/users/:id
Body Parser
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.
Multipart
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,
        },
      },
    },
    // ...
  },
  //...
});XML And Text
Same as multipart, you need to enable them by xmlOpts and textOpts configs.
More options
Check more options in config types.
Responses
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,
      };
    },
  },
});Validate
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
  },
});Static File Serve
Serve /assets directory like this:
nico.init({
  serve: {
    root: path.resolve(process.cwd(), './assets'),
  },
});Change Route Path
nico.init({
  serve: {
    root: path.resolve(process.cwd(), './assets'),
    route: '/static',
  },
});Get /assets/avatar.png by route {{serverUrl}}/static/avatar.png.
Serve Multiple Directories
Serve multiple directories also supported.
nico.init({
  serve: [
    {
      root: path.resolve(process.cwd(), './assets'),
      route: '/assets',
    },
    {
      root: path.resolve(process.cwd(), './static'),
      route: '/static',
    },
  ],
});More Options
Serve configs support koa-static options.
nico.init({
  serve: {
    opts, // from koa-static
  },
});Debug
nico has five log levels: fatal, error, warn, info, debug and trace.
Default console level is info, file level is none.
Logger
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({
  // ...
});Custom Middlewares
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.
Graceful Shutdown
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.
Cluster Mode
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.
Plugins
- nico-build bundle project build on nico.
 - nico-mongo (⚠️building) use mongo with nico.
 - nico-redis (⚠️building) use ioredis with nico.
 
License
2 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
4 years ago
4 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago