New release is coming soon! If you want to try out the latest features, simply run npm i -s moleculer@next. The docs for the latest version are available here.
GET /api/hi => test.hello GET /api/v2/posts => v2.posts.list GET /api/v2/posts/:id => v2.posts.get POST /api/v2/posts => v2.posts.create PUT /api/v2/posts/:id => v2.posts.update DELETE /api/v2/posts/:id => v2.posts.remove
嵌套对象和数组 URL: GET /api/opt-test?foo[bar]=a&foo[bar]=b&foo[baz]=c
foo: { bar: ["a", "b"], baz: "c" }
中间件
It supports Connect-like middlewares in global-level, route-level & alias-level. Signature: function(req, res, next) {...}. For more info check express middleware
示例
broker.createService({ mixins: [ApiService], settings: { // Global middlewares. Applied to all routes. use: [ cookieParser(), helmet() ],
There is support to use error-handler middlewares in the API Gateway. So if you pass an Error to the next(err) function, it will call error handler middlewares which have signature as (err, req, res, next).
broker.createService({ mixins: [ApiService], settings: { // Global middlewares. Applied to all routes. use: [ cookieParser(), helmet() ],
routes: [ { path: "/",
// Route-level middlewares. use: [ compression(),
passport.initialize(), passport.session(),
function(err, req, res, next) { this.logger.error("Error is occured in middlewares!"); this.sendError(req, res, err); } ],
Serve static files
It serves assets with the serve-static module like ExpressJS.
// Further options to `serve-static` module options: {} } } });
Calling options
The route has a callOptions property which is passed to broker.call. So you can set timeout, retries or fallbackResponse options for routes. Read more about calling options
Please note that you can also set the timeout for an action directly in its definition
You can create multiple routes with different prefix, whitelist, alias, calling options & authorization.
When using multiple routes you should explicitly set the body parser(s) for each route.
broker.createService({ mixins: [ApiService],
settings: { routes: [ { path: "/admin",
authorization: true,
whitelist: [ "$node.*", "users.*", ],
bodyParsers: { json: true } }, { path: "/",
whitelist: [ "posts.*", "math.*", ],
bodyParsers: { json: true } } ] } });
Response type & status code
When the response is received from an action handler, the API gateway detects the type of response and set the Content-Type in the res headers. The status code is 200 by default. Of course you can overwrite these values, moreover, you can define custom response headers, too.
To define response headers & status code use ctx.meta fields:
Available meta fields:
ctx.meta.$statusCode - set res.statusCode.
ctx.meta.$statusMessage - set res.statusMessage.
ctx.meta.$responseType - set Content-Type in header.
ctx.meta.$responseHeaders - set all keys in header.
ctx.meta.$location - set Location key in header for redirects.
示例
module.exports = { name: "export", actions: { // Download response as a file in the browser downloadCSV(ctx) { ctx.meta.$responseType = "text/csv"; ctx.meta.$responseHeaders = { "Content-Disposition": `attachment; filename="data-${ctx.params.id}.csv"` };
methods: { // Second thing authorize(ctx, route, req, res) { // Read the token from header let auth = req.headers["authorization"]; if (auth && auth.startsWith("Bearer")) { let token = auth.slice(7);
// Check the token if (token == "123456") { // Set the authorized user entity to `ctx.meta` ctx.meta.user = { id: 1, name: "John Doe" }; returnPromise.resolve(ctx);
} else { // No token returnPromise.reject(new E.UnAuthorizedError(E.ERR_NO_TOKEN)); } }
} }
You can find a more detailed role-based JWT authorization example in full example.
Authentication
To enable the support for authentication, you need to do something similar to what is describe in the Authorization paragraph. Also in this case you have to:
Set authentication: true in your routes
Define your custom authenticate method in your service
The returned value will be set to the ctx.meta.user property. You can use it in your actions to get the logged in user entity.
methods: { authenticate(ctx, route, req, res) { let accessToken = req.query["access_token"]; if (accessToken) { if (accessToken === "12345") { // valid credentials. It will be set to `ctx.meta.user` returnPromise.resolve({ id: 1, username: "john.doe", name: "John Doe" }); } else { // invalid credentials returnPromise.reject(); } } else { // anonymous user returnPromise.resolve(null); } } } });
Route hooks
The route has before & after call hooks. You can use it to set ctx.meta, access req.headers or modify the response data.
broker.createService({ mixins: [ApiService],
settings: { routes: [ { path: "/",
onBeforeCall(ctx, route, req, res) { // Set request headers to context meta ctx.meta.userAgent = req.headers["user-agent"]; },
onAfterCall(ctx, route, req, res, data) { // Async function which return with Promise return doSomething(ctx, res, data); } } ] } });
In previous versions of Moleculer Web, you couldn’t manipulate the data in onAfterCall. Now you can, but you must always return the new or original data.
Error handlers
You can add route-level & global-level custom error handlers.
In handlers, you must call the res.end. Otherwise, the request is unhandled.
API gateway implements a helper function that formats the error. You can use it to filter out the unnecessary data.
broker.createService({ mixins: [ApiService], methods: { reformatError(err) { // Filter out the data from the error before sending it to the client return _.pick(err, ["name", "message", "code", "type", "data"]); }, } }
CORS headers
You can use CORS headers in Moleculer-Web service.
// Global CORS settings for all routes cors: { // Configures the Access-Control-Allow-Origin CORS header. origin: "*", // Configures the Access-Control-Allow-Methods CORS header. methods: ["GET", "OPTIONS", "POST", "PUT", "DELETE"], // Configures the Access-Control-Allow-Headers CORS header. allowedHeaders: [], // Configures the Access-Control-Expose-Headers CORS header. exposedHeaders: [], // Configures the Access-Control-Allow-Credentials CORS header. credentials: false, // Configures the Access-Control-Max-Age CORS header. maxAge: 3600 },
// Call after `broker.call` and before send back the response onAfterCall(ctx, route, req, res, data) { res.setHeader("X-Custom-Header", "123456"); return data; },
This service method (this.addRoute(opts, toBottom = true)) add/replace a route. For example, you can call it from your mixins to define new routes (e.g. swagger route, graphql route, etc.).
Please note that if a route already exists this method will replace previous route configuration with a new one.
removeRoute
Service method removes the route by path (this.removeRoute("/admin")).