• 设为首页
  • 点击收藏
  • 手机版
    手机扫一扫访问
    迪恩网络手机版
  • 关注官方公众号
    微信扫一扫关注
    迪恩网络公众号

raveljs/ravel: Forge past a tangle of node.js modules. Make a cool app.

原作者: [db:作者] 来自: 网络 收藏 邀请

开源软件名称:

raveljs/ravel

开源软件地址:

https://github.com/raveljs/ravel

开源编程语言:

JavaScript 96.6%

开源软件介绍:

Ravel

Forge past a tangle of modules. Make a cool app.

GitHub license npm version Dependency Status npm Build Status Build status Test Coverage js-semistandard-style

Ravel is a tiny, sometimes-opinionated foundation for creating organized, maintainable, and scalable web applications in node.js with ES2016/2017.

Note: The main branch may be in an unstable or even broken state during development. Please use releases instead of the main branch to explore stable code.

Table of Contents

Introduction

Ravel is inspired by the simplicity of koa and express, but aims to provide a pre-baked, well-tested and highly modular solution for creating enterprise web applications by providing:

  • A standard set of well-defined architectural components so that your code stays organized
  • Rapid REST API definition
  • Easy bootstrapping via an enforced, reference configuration of koa with critical middleware
  • Dependency injection (instead of relative requires)

And a few other features, plucked from popular back-end frameworks:

  • Transaction-per-request
  • Simple authentication and authentication configuration (no complex passport setup)
  • (Optional) externalized session storage for horizontal scalability

Ravel is deliberately designed to minimize unnecessary dependencies and have a small, well-documented codebase, making it easier to create secure and robust applications you and your users can trust.

Ravel is layered on top of, and designed to be used with, awesome technologies, including:

Installation

As Ravel uses async/await and several other ES2015/2016 features, you will need to use a 8.0.x+ distribution of node

$ npm install ravel

Architecture

Ravel applications consist of a few basic parts:

  • Modules: plain old classes which offer a great place to define modular application logic, middleware, authentication logic, etc.
  • Middleware a familiar concept from express or koa-like frameworks, middleware are chained functions which run in sequence against a request to a specific route.
  • Routes: a low-level place for general routing logic
  • Resources: built on top of Routes, Resources are REST-focused
  • Errors: Node.js Errors which are associated with an HTTP response code. throw them in your code and Routes and Resources will automatically produce responses with a matching status.

If you're doing it right, your applications will consist largely of Modules, with a thin layer of Routes and Resources on top.

Modules (and Errors)

Modules are plain old node.js modules exporting a single class which encapsulates application logic. Modules support dependency injection of core Ravel services and other Modules alongside npm dependencies (no relative require's!). Modules are instantiated safely in dependency-order, and cyclical dependencies are detected automatically.

For more information about Modules, look at Ravel.Module below.

modules/cities.js

const Ravel = require('ravel');
const Error = Ravel.Error;
const Module = Ravel.Module;
const inject = Ravel.inject;

/**
 * First, we'll define an Error we will throw when a requested
 * city is not found. This Error will be associated with the
 * HTTP error code 404.
 */
class MissingCityError extends Error {
  constructor (name) {
    super(`City ${name} does not exist.`, Ravel.httpCodes.NOT_FOUND);
  }
}

/**
 * Our main Module, defining logic for working with Cities
 */
@inject('moment', '$log')
@Module('cities')
class Cities {
  constructor (moment, $log) {
    this.moment = moment;
    this.$log = $log
    this.cities = ['Toronto', 'New York', 'Chicago']; // our fake 'database'
  }

  getAllCities () {
    return Promise.resolve(this.cities);
  }

  getCity (name) {
    return new Promise((resolve, reject) => {
      const index = this.cities.indexOf(name);
      if (index !== -1) {
        resolve(this.cities[index]);
      } else {
        // Ravel will automatically respond with the appropriate HTTP status code!
        this.$log.warn(`User requested unknown city ${name}`);
        reject(new MissingCityError(name));
      }
    });
  }
}

// Export Module class
module.exports = Cities;

Middleware

Ravel middleware takes the form of an async function and is defined within Modules, either directly or via a factory pattern:

modules/cities.js

const Ravel = require('ravel');
const Module = Ravel.Module;
const middleware = Module.middleware;
class MyMiddleware {
  // this middleware will be available by name elsewhere in the application
  @middleware('custom-middleware')
  async doSomething(ctx, next) {
    // ... do something before the next middleware runs
    await next();
    // ... do something after the next middlware runs
  }

  // this middleware is also available elsewhere by name,
  // but is a factory that can receive two arguments
  @middleware('another-middleware', { factory: true })
  anotherMiddlewareFactory (arg1, arg2) {
    return async (ctx, next) {
      await next();
    }
  }
}

Routes

Routes are Ravel's lower-level wrapper for koa (Resources are the higher-level one). They support HEAD, GET, POST, PUT, PATCH and DELETE requests, and middleware, via decorators. Like Modules, they also support dependency injection. Though Routes can do everything Resources can do, they are most useful for implementing non-REST things, such as static content serving, proxying, etc. If you want to build a REST API, use Resources instead (they're up next!).

For more information about Routes, look at Ravel.Routes below.

routes/index.js

const Ravel = require('ravel');
const Routes = Ravel.Routes;
const inject = Ravel.inject;
const before = Routes.before; // decorator to chain middleware before an endpoint
const mapping = Routes.mapping; // decorator to associate a handler method with an endpoint

@Routes('/') // base path for all routes in this class. Will be prepended to the @mapping.
class ExampleRoutes {
  // bind this method to an endpoint and verb with @mapping. This one will become GET /app
  @mapping(Routes.GET, 'app')
  @before('custom-middleware') // use @before to place multiple middleware (comma-separated names) before appHandler - these could be npm modules, functions on this scope, or defined via @middleware
  async appHandler (ctx) {
    // ctx is just a koa context! Have a look at the koa docs to see what methods and properties are available.
    ctx.body = '<!DOCTYPE html><html><body>Hello World!</body></html>';
    ctx.status = 200;
  }

  @mapping(Routes.GET, 'log')
  @before('another-middleware', 1, 2, 'custom-middleware') // use @before to instantiate middleware which accepts arguments, alongside middleware which doesn't.
  async logHandler (ctx) {
    // ...
  }
}

// Export Routes class
module.exports = ExampleRoutes;

Resources

What might be referred to as a controller in other frameworks, a Resource module defines HTTP methods on an endpoint, supporting the session-per-request transaction pattern via Ravel middleware. Resources also support dependency injection, allowing for the easy creation of RESTful interfaces to your Module-based application logic. Resources are really just a thin wrapper around Routes, using specially-named handler functions (get, getAll, head, headAll, post, put, putAll, patch, patchAll, delete, deleteAll) instead of @mapping. This convention-over-configuration approach makes it easier to write proper REST APIs with less code, and is recommended over "carefully chosen" @mappings in a Routes class.

For more information about Resources, look at Ravel.Resource below.

resources/city.js

// Resources support dependency injection too!
// Notice that we have injected our cities Module by name.
const Ravel = require('ravel');
const Resource = Ravel.Resource;
const inject = Ravel.inject;
const before = Resource.before; // decorator to add middleware to an endpoint within the Resource

// using @before at the class level decorates all endpoint methods with middleware
@inject('cities')
@Resource('/cities') // base path for all routes in this Resource
class CitiesResource {
  constructor (cities) {
    this.cities = cities;
  }

  // no need to use @mapping here. Routes methods are automatically mapped using their names.
  async getAll (ctx) { // just like in Routes, ctx is a koa context.
    ctx.body = await this.cities.getAllCities();
  }

  @before('custom-middleware') // using @before at the method level decorates this method with middleware
  @before('another-middleware', 1, 2) // use @before multiple times for clarity, if desired
  async get (ctx) { // get routes automatically receive an endpoint of /cities/:id (in this case).
    ctx.body = await this.cities.getCity(ctx.params.id);
  }

  // post, put, putAll, delete and deleteAll are
  // also supported. Not specifying them for
  // this resource will result in calls using
  // those verbs returning HTTP 501 NOT IMPLEMENTED

  // postAll is not supported, because it makes no sense
}

// Export Resource class
module.exports = CitiesResource;

Bringing it all together

app.js

const app = new require('ravel')();

// parameters like this can be supplied via a .ravelrc.json file
app.set('keygrip keys', ['mysecret', 'anothersecret']);

app.scan('./modules'); //import all Modules from a directory
app.scan('./resources');  //import all Resources from a directory
app.scan('./routes/index.js');  //import all Routes from a file

// start it up!
app.start();

Decorator Transpilation

Since decorators are not yet available in Node, you will need to use a transpiler to convert them into ES2016-compliant code. We have chosen Babel as our recommended transpiler.

gulpfile.js

const babelConfig = {
  'plugins': [['@babel/plugin-proposal-decorators', { 'legacy': true }]]
};
gulp.task('transpile', function () {
  return gulp.src('src/**/*.js') // point it at your source directory, containing Modules, Resources and Routes
      .pipe(plugins.babel(babelConfig))
      .pipe(gulp.dest('dist'));  // your transpiled Ravel app will appear here!
});

Running the Application

$ node dist/app.js

API Documentation

View API docs


鲜花

握手

雷人

路过

鸡蛋
该文章已有0人参与评论

请发表评论

全部评论

专题导读
热门推荐
阅读排行榜

扫描微信二维码

查看手机版网站

随时了解更新最新资讯

139-2527-9053

在线客服(服务时间 9:00~18:00)

在线QQ客服
地址:深圳市南山区西丽大学城创智工业园
电邮:jeky_zhao#qq.com
移动电话:139-2527-9053

Powered by 互联科技 X3.4© 2001-2213 极客世界.|Sitemap