README

mhagmajer:server-router

Server router with authentication for Meteor

Introductory blog post: https://blog.hagmajer.com/server-side-routing-with-authentication-in-meteor-6625ed832a94.

Documentation: https://mhagmajer.github.io/server-router/.

Compatibility

Please beware that:

  • versions 1.2.x and above require Meteor 1.6.1+
  • versions 1.1.x and below require Meteor 1.4.4.2-1.6

Installing

meteor add mhagmajer:server-router

You can find Flow type definitions in /definitions.

Example

Server-side

import { ServerRouter } from 'meteor/mhagmajer:server-router';

WebApp.connectHandlers.use(ServerRouter.middleware({
  paths: [],
  routes: {
    hello(name) {
      this.res.end(`You ${name}, your id is ${this.userId}`);
    },
  },
}));

Client-side

import { ServerRouterClient } from 'meteor/mhagmajer:server-router';

const serverRouterClient = new ServerRouterClient({
  routes: {
    hello: 1,
  },
});

<Button onClick={() => {
  serverRouterClient.redirect.hello('John');  
}} />

Publishing (contributors)

Run npm run clean before meteor publish.

Types

Path

Basic object of the router representing a server-side path available via HTTP request. For each path matching the request url, a handler (Route) is called with this bound to the context of the request (ServerRouterContext).

Initalized with the following data:

  • path (string): url path in format acceptable by path-to-regexp.
  • options: Optional data passed to path-to-regexp.

    • sensitive (string = false): When true the path will be case sensitive.
    • strict (string = false): When false the trailing slash is optional.
    • end (string = false): When false the path will match at the beginning.
    • delimiter (string = /): Set the default delimiter for repeat parameters.
  • args (ArgsMapper) mapper of params and query to route arguments.
  • route (Route) function to be called when path matches.
Path

Type: {path: string, options: {sensitive: boolean?, strict: boolean?, end: boolean?, delimiter: string?}?, args: ArgsMapper, route: Route}

Properties
path (string)
options ({sensitive: boolean?, strict: boolean?, end: boolean?, delimiter: string?}?)
options.sensitive (boolean?)
options.strict (boolean?)
options.end (boolean?)
options.delimiter (string?)
args (ArgsMapper)
route (Route)
Example
serverRouter.addPath({
  path: '/binary-representation/:n',
  args: ({ n }) => [Number(n)],
  async route(n) {
    this.res.end(n.toString(2));
  },
});
// GET /binary-representation/1337
// 10100111001
serverRouter.addPath({
  path: '/sum/:n+',
  args: ({ n }) => n.map(Number),
  async route(...nums) {
    this.res.end(String(nums.reduce((a, b) => a + b)));
  },
});
// GET /sum/1/2/3
// 6
serverRouter.addPath({
  path: '/get-query',
  args: (params, query) => [query],
  async route(query) {
    this.res.end(String(Object.keys(query)));
  },
});
// GET /get-query?a=&b=
// a,b

ArgsMapper

Function used to map params and query to actual route arguments.

ArgsMapper

Type: function (params: {}, query: {}): Array<any>

Parameters
params (ObjectMap<string, (string | Array<string>)>) name parameters matched in path.
query (ObjectMap<string, string>) url query parameters (following ? ).
Returns
Array<any>: arguments that the route will be called with.

Route

Path handler called with this bound to ServerRouterContext.

In order to respond to HTTP request, you should write to this.res object. By default, request processing is finished once your handler finishes. If you want to disable this behavior, you can return false to pass the processing to the next handler. Note that the response (this.res) must eventually be ended during the HTTP request processing by a route within ServerRouter or some other middleware.

Any exceptions thrown in handlers other than AuthenticationRequiredError are presented in response.

Route

Type: function (): Promise<(void | boolean)>

Returns
Promise<(boolean | void)>: whether the request processing is complete (defaults to true).
Throws
  • AuthenticationRequiredError: if access to this route requires authentication. It will cause this route to be called again with this.userId to be set to the current user (if any).

ServerRouterContext

Object to which this is bound to inside your Route invocation. It provides the following:

  • req (IncomingMessage): information about the incoming request.
  • res (ServerResponse): use this to write data that should be sent in response to the request.
  • userId (string?): the id of the current user.

This object is preserved between calling matched routes, so you can augment it.

ServerRouterContext

Type: {req: IncomingMessage, res: ServerResponse, userId: string?}

Properties
req (IncomingMessage)
res (ServerResponse)
userId (string?)

Routes

Nested dictionary of Route functions. This allows for namespaces.

Routes

Type: {}

Example
serverRouter.addRoutes({
  reports: {
    salesPDF, // available by name 'reports.salesPDF'
    employeesPDF,
  },
  images: {
    pngs: {
      async logo() { ... }, // name: 'images.pngs.logo'
    },
  },
});

Classes

ServerRouter

Server-side routing provider of the connect API that can be used with Meteor webapp package.

new ServerRouter(options: {routes: Routes?, defaultRoutePath: string?, paths: Array<Path>?})
Parameters
options ({routes: Routes?, defaultRoutePath: string?, paths: Array<Path>?})
Name Description
options.paths Array<Path>? (default []) Initial paths. You can add more with #ServerRouter#addPaths or #ServerRouter#addPath .
options.routes Routes? (default {}) Initial routes. You can add more with #ServerRouter#addRoutes .
options.defaultRoutePath string? (default /r/:name/:args*) Any added Route can be reached by this path when provided its nested name and arguments. See Path for more on syntax. Should be unique for every ServerRouter instance (if you need more than one). Arguments are serialized with EJSON for transportation.
Example
WebApp.connectHandlers.use((new ServerRouter({
  routes: { ... },
  paths: [ ... ],
})).middleware);
WebApp.connectHandlers.use(ServerRouter.middleware({
  routes: { ... },
  paths: [ ... ],
}));
const serverRouter = new ServerRouter();
WebApp.connectHandlers.use(serverRouter.middleware);

serverRouter.addPaths([ ... ]);
serverRouter.addRoutes({ ... });
Static Members
middleware(options)
Instance Members
addPath(data)
addPaths(data)
addRoutes(routes)
middleware

AuthenticationRequiredError

Thrown by routes when authentication is required for further processing.

new AuthenticationRequiredError()

ServerRouterClient

Client for ServerRouter

new ServerRouterClient(options: {routes: R?, defaultRoutePath: string?})
Parameters
options ({routes: R?, defaultRoutePath: string?})
Name Description
options.routes Routes (default {}) Known server-side routes. When providing this object you can substitute function with anything other than object. For example:
const x: any = 1;
const routes: Routes = {
  Reports: {
    genReport: x,
    genReport2: x,
  },
};

This is used to populate #ServerRouterClient#url and

options.defaultRoutePath string (default /r/:name/:args*) Same as in ServerRouter .
Instance Members
redirect
path
redirectTo(path)
redirectToRoute(name, args)
authenticatePath(path)
getRoutePath(name, args)