All Projects → ysocorp → koa-smart

ysocorp / koa-smart

Licence: other
A framework base on Koajs2 with Decorator, Params checker and a base of modules (cors, bodyparser, compress, I18n, etc…) to let you develop smart api easily

Programming Languages

typescript
32286 projects
javascript
184084 projects - #8 most used programming language

Projects that are alternatives of or similar to koa-smart

Koa Dec Router
An ES6 decorator + class based router, support inherit, override, priority, auto load controllers, etc.
Stars: ✭ 19 (-38.71%)
Mutual labels:  decorators, class, koa2
Koahub Demo
koahub+async/await+mysql
Stars: ✭ 15 (-51.61%)
Mutual labels:  koajs, koa2
stack
A set of components for makers to ship better products faster 🚀
Stars: ✭ 27 (-12.9%)
Mutual labels:  koajs, koa2
reducer-class
Boilerplate free class-based reducer creator. Built with TypeScript. Works with Redux and NGRX. Has integration with immer.
Stars: ✭ 25 (-19.35%)
Mutual labels:  decorators, class
Eggjs Note
《Egg.js 深入浅出学习笔记》(暂时停更)
Stars: ✭ 502 (+1519.35%)
Mutual labels:  koajs, koa2
Koajs Design Note
《Koa.js 设计模式-学习笔记》已完结 😆
Stars: ✭ 520 (+1577.42%)
Mutual labels:  koajs, koa2
Cool Admin Api
cool-admin-api 是基于egg.js、typeorm、jwt等封装的api开发脚手架、快速开发api接口
Stars: ✭ 188 (+506.45%)
Mutual labels:  koajs, koa2
restria
Entria's REST API boilerplate
Stars: ✭ 25 (-19.35%)
Mutual labels:  koajs, koa2
Class Logger
Boilerplate-free decorator-based class logging
Stars: ✭ 64 (+106.45%)
Mutual labels:  decorators, class
Trafficlight
🚦 Flexible NodeJS Routing Decorators for API Routing
Stars: ✭ 69 (+122.58%)
Mutual labels:  decorators, koa2
Koa2 Note
《Koa2进阶学习笔记》已完结🎄🎄🎄
Stars: ✭ 4,725 (+15141.94%)
Mutual labels:  koajs, koa2
koahub-cli
KoaHub CLI -- KoaHub.js的开发工具,自动babel编译 ES6/7(Generator Function, Class, Async & Await)并且文件修改后自动重启。
Stars: ✭ 16 (-48.39%)
Mutual labels:  koajs, koa2
Koahub
KoaHub.js -- 中文最佳实践Node.js Web快速开发框架。支持Koa.js, Express.js中间件。当前项目已停止维护,推荐使用Doodoo.js
Stars: ✭ 308 (+893.55%)
Mutual labels:  koajs, koa2
Vue Chat
👥Vue全家桶+Socket.io+Express/Koa2打造一个智能聊天室。
Stars: ✭ 887 (+2761.29%)
Mutual labels:  koajs, koa2
polix
🚀 Node.js Web Framework
Stars: ✭ 32 (+3.23%)
Mutual labels:  koajs, koa2
Koach Javascript
Production ready Koa2 boilerplate.
Stars: ✭ 79 (+154.84%)
Mutual labels:  koajs, koa2
toxic-decorators
Library of Javascript decorators
Stars: ✭ 26 (-16.13%)
Mutual labels:  decorators, class
Python And Oop
Object-Oriented Programming concepts in Python
Stars: ✭ 123 (+296.77%)
Mutual labels:  decorators, class
koa-orm
koa orm using sequelize & sk2 (fork from knex)
Stars: ✭ 62 (+100%)
Mutual labels:  koajs, koa2
tododjangoccb
A todo application with django web framework with class based views and ajax modal crud
Stars: ✭ 32 (+3.23%)
Mutual labels:  class

KoaSmart is a framework based on Koajs2, which allows you to develop RESTful APIs with : Class, Decorator, Params checker

Build Status NPM version

A framework based on Koajs2 with Decorator, Params checker and a base of modules (cors, bodyparser, compress, I18n, etc... ) to allow you to develop a smart api easily

  export default class RouteUsers extends Route {

    // get route: http://localhost:3000/users/get/:id
    @Route.Get({
      path: 'get/:id'
    })
    async get(ctx) {
      const user = await this.models.users.findById(ctx.params.id);
      this.assert(user, 404, 'User not found');
      this.sendOk(ctx, user);
    }

    // post route: http://localhost:3000/users/add
    @Route.Post({
      accesses: [Route.accesses.public],
      bodyType: Types.object().keys({
        email: Types.string().required(), // return an 400 if the body doesn't contain email key
        name: Types.string().uppercase(), // optional parameter
      }),
    })
    async add(ctx) {
      const body = this.body(ctx); // or ctx.request.body
      // body can contain only an object with email and name field
      const user = await this.models.user.create(body);
      this.sendCreated(ctx, user);
    }

  }

Api documentation

Summary

What is in this framework ?

**This framework gives you the tools to use a set of modules: **

Install

npm install --save koa-smart Or use the boilerplate (koa-smart-boilerplate)

Router with decorator

All routes have to extend the Route class in order to be mount

  • Prefix of routes

    If you have a route class with the name RouteMyApi, all the routes inside said class will be preceded by /my-api/

    • How does it work ?

      1. the Route word is removed
      2. uppercase letters are replaced with '-'. (essentially converting camelCase into camel-case) e.g.: this will add a get route => http://localhost:3000/my-api/hello
      export default class RouteMyApi extends Route {
      
          @Route.Get({})
          async hello(ctx) {
              this.sendOk(ctx, 'hello');
          }
      
      }
    • Change prefix of all routes in the class: http://localhost:3000/my-prefix/hello

      @Route.Route({
          routeBase: 'my-prefix',
      })
      export default class RouteMyApi extends Route {
      
          @Route.Get({})
          async hello(ctx) {
              this.sendOk(ctx, 'hello');
          }
      
      }
  • Get route http://localhost:3000/my-api/hello

      @Route.Get({})
      async hello(ctx) {
        this.sendOk(ctx, null, 'hello');
      }
  • Change path http://localhost:3000/my-api/myroute/15

      @Route.Get({
        path: '/myroute/:id'
      })
      async hello(ctx) {
        this.sendOk(ctx, 'hello' + ctx.params.id);
      }
  • Post route http://localhost:3000/my-api/user-post

      @Route.Post({
        bodyType: Types.object().keys({ // body to allow: all other params will be rejected
          email: Types.string().required(), // return an 400 if the body doesn't contain email key
          name: Types.string().uppercase(), // optional parameter
        }),
      })
      async userPost(ctx) {
        const body = this.body(ctx);
        // body can contain only an object with email and name field
        const user = await this.models.user.create(body);
        this.sendCreated(ctx, user);
      }
  • Disable route

    • Disable all routes in a class

      to disable all routes in a class you should add disable in the content of your decorator class

      @Route.Route({
          disable: true,
      })
      export default class RouteMyApi extends Route {
          // All routes in this class will not be mounted
      }
    • Disable a specific route

      to disable a specific route you can add disable in the content of your decorator

      @Route.Get({
          disable: true, // this route will not be mounted
      })
      async hello(ctx) {
        this.sendOk(ctx, null, 'hello');
      }
  • Grant accesses

    Koa smart allows grant permission to be handled in a simple and efficient manner.

    Each function passed to accessers will be given the koa context (ctx) as a parameter, and must return a boolean to express whether is grants access to the route or not.

    If at least one of the function given returns true, access to the route will be granted.

      async function isConnected(ctx) {
        // TODO test if the user is connected
        return ctx.state.user;
      }
      async function isUserPremium(ctx) {
        // TODO test if the user is premium
        return ctx.state.user.isPremium;
      }
      async function isAdmin(ctx) {
        // TODO test if the user is a admin
        return ctx.state.user.isAdmin;
      }
    • Of a Class

      @Route.Route({ accesses: [isConnected] })
      class RouteMiddlewares extends Route {
        @Route.Get({})
        async view(ctx, next) {
          console.log('I can be call if the current client is connected');
          this.sendOk(ctx, null, 'OK');
        }
      }
    • Of a specific route

      @Route.Get({})
      async myPublicRoute(ctx, next) {
        console.log('I am a public route, I can be call by any one');
        this.sendOk(ctx, null, 'OK');
      }
      
      @Route.Get({ accesses: [isConnected] })
      async myConnectedRoute(ctx, next) {
        console.log('I can be call if the current client is connected');
        this.sendOk(ctx, null, 'OK');
      }
      
      @Route.Get({ accesses: [isUserPremium, isAdmin] })
      async myPremiumRoute(ctx, next) {
        console.log('I can be call if the current client is connected and premium or admin');
        this.sendOk(ctx, null, 'OK');
      }
  • RateLimit : For more infos, see the koa2-ratelimit module

    • Configure

      import { App } from 'koa-smart';
      import { RateLimit, RateLimitStores } from 'koa-smart/middlewares';
      
      const app = new App({ port: 3000 });
      
      // Set Default Option
      const store = new RateLimitStores.Memory() OR new RateLimitStores.Sequelize(sequelizeInstance)
      RateLimit.defaultOptions({
          message: 'Too many requests, get out!',
          store: store, // By default it will create MemoryStore
      });
      
      // limit 100 accesses per min on your API
      app.addMiddlewares([
        // ...
        RateLimit.middleware({ interval: { min: 1 }, max: 100 }),
        // ...
      ]);
    • RateLimit On Decorator

      Single RateLimit

      @Route.Get({ // allow only 100 requests per day to /view
          rateLimit: { interval: { day: 1 }, max: 100 },
      })
      async view(ctx) {
        this.sendOk(ctx, null, 'hello');
      }

      Multiple RateLimit

      // Multiple RateLimit
      @Route.Get({
          rateLimit: [
              { interval: { day: 1 }, max: 100 }, // allow only 100 requests per day
              { interval: { min: 2 }, max: 40 }, // allow only 40 requests in 2 minutes
          ],
      })
      async hello(ctx) {
        this.sendOk(ctx, null, 'hello');
      }
  • Middlewares

    • Of a Class

      @Route.Route({
          middlewares: [ // Array of middlewares
            async (ctx, next) => {
              console.log('I will be call before all route in this class');
              await next();
            },
          ],
      })
      class RouteMiddlewares extends Route {
          @Route.Get({})
          async view(ctx, next) {
            console.log('I will be call after middlewares of class');
            this.sendOk(ctx, null, 'hello');
          }
      }
    • Of a specific route

      @Route.Get({
          middlewares: [ // Array of middlewares
            async (ctx, next) => {
              console.log('I will be call before the route but after middlewares of class');
              await next();
            },
          ],
      })
      async view(ctx, next) {
          console.log('I will be call after middlewares of the class and route');
          this.sendOk(ctx, null, 'hello');
      }

Params checker: See the doc of Types for more information

  • bodyType to check body params

    • quick example

        @Route.Post({ // or Put, Patch
          bodyType: Types.object().keys({
            email: Types.string().regex(/\S+@\S+\.\S+/).required(),
            password: Types.string().min(8).required(),
            address: Types.object().keys({
              country: Types.string().required(),
              street: Types.string().required(),
            }).required(),
          }),
        })
        async user(ctx) {
          // this is the body manage by bodyType
          const bodyParams = this.body(ctx);
      
          // this is the origin body pass
          const originBodyParams = this.body(ctx, true);
        }
  • queryType to check query params

    • quick example

        @Route.Get({
          queryType: Types.object().keys({
            limit: Types.number().integer().required().default(10),
            offset: Types.number().integer().required().default(10),
          }),
        })
        async users(ctx) {
          // this can contain only limit and offset
          const queryParams = this.queryParam(ctx);
      
          // this is the origin queryParams pass
          const originQueryParams = this.queryParam(ctx, true);
        }

Automatic documention generation: See the manual for more information

Get Started (quick-start boilerplate)

in order to get started quickly, look at this boilerplate, or follow the instructions below:

  • import the app and your middlewares

    import { join } from 'path';
    // import the app
    import { App } from 'koa-smart';
    // import middlewares koa-smart give you OR others
    import {
      bodyParser,
      compress,
      cors,
      handleError,
      RateLimit,
      ...
    } from 'koa-smart/middlewares';
  • create an app listening on port 3000

    const myApp = new App({
      port: 3000,
    });
  • add your middlewares

    myApp.addMiddlewares([
      cors({ credentials: true }),
      helmet(),
      bodyParser({ multipart: true }),
      handleError(),
      RateLimit.middleware({ interval: { min: 1 }, max: 100 }),
      ...
    ]);
  • add your routes mount a folder with a prefix (all file who extends from Route will be added and mounted)

        myApp.mountFolder(join(__dirname, 'routes'), '/');
  • Start your app

    myApp.start();

Full example

  • Basic one

    import { join } from 'path';
    // import the app
    import { App } from 'koa-smart';
    // import middlewares koa-smart give you OR others
    import {
      i18n,
      bodyParser,
      compress,
      cors,
      helmet,
      addDefaultBody,
      handleError,
      logger,
      RateLimit,
    } from 'koa-smart/middlewares';
    
    const myApp = new App({
      port: 3000,
    });
    
    myApp.addMiddlewares([
      cors({ credentials: true }),
      helmet(),
      bodyParser({ multipart: true }),
      i18n(myApp.app, {
        directory: join(__dirname, 'locales'),
        locales: ['en', 'fr'],
        modes: ['query', 'subdomain', 'cookie', 'header', 'tld'],
      }),
      handleError(),
      logger(),
      addDefaultBody(),
      compress({}),
      RateLimit.middleware({ interval: { min: 1 }, max: 100 }),
    ]);
    
    // mount a folder with an prefix (all file who extends from `Route` will be add and mount)
    myApp.mountFolder(join(__dirname, 'routes'), '/');
    
    // start the app
    myApp.start();
  • Other example who Extends class App

    import { join } from 'path';
    // import the app
    import { App } from 'koa-smart';
    // import middlewares koa-smart give you OR others
    import {
      i18n,
      bodyParser,
      compress,
      cors,
      helmet,
      addDefaultBody,
      handleError,
      logger,
      RateLimit,
    } from 'koa-smart/middlewares';
    
    // create an class who extends from App class
    export default class MyApp extends App {
      constructor() {
        super({ port: 3000 });
      }
    
      async start() {
        // add your Middlewares
        super.addMiddlewares([
          cors({ credentials: true }),
          helmet(),
          bodyParser({ multipart: true }),
          i18n(this.app, {
            directory: join(__dirname, 'locales'),
            locales: ['en', 'fr'],
            modes: ['query', 'subdomain', 'cookie', 'header', 'tld'],
          }),
          handleError(),
          logger(),
          addDefaultBody(),
          compress({}),
          RateLimit.middleware({ interval: { min: 1 }, max: 100 }),
        ]);
    
        // mount a folder with an prefix (all file who extends from `Route` will be add and mount)
        super.mountFolder(join(__dirname, 'routes'));
        return super.start();
      }
    }
    
    // start the app
    const myApp = new MyApp();
    myApp.start();

Upgrade to 4.0.0

4.0.0 upgrades koa2-ratelimit to version 1.0.0

This means koa2-ratelimit does not install sequelize, mongoose or redis anymore. If you use these packages, make sure you install them in your project.

License

MIT © YSO Corp

Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].