1.1.3 • Published 7 years ago

@helpfulhuman/router-kit v1.1.3

Weekly downloads
1
License
MIT
Repository
github
Last release
7 years ago

Router Kit

Router Kit is meant to be a toolkit for building custom routing solutions for front-end, single page web applications. It provides a simple, middleware-based architecture for handling window.location changes. Router Kit does not include any particular implementation for tracking location changes, so you'll likely want to use a library like history for that.

Getting Started

Install via npm:

npm install --save @helpfulhuman/router-kit

The Router Class

This library provides you with a Router object for attaching middleware and route handlers for your application.

import { Router } from "@helpfulhuman/redux-router";

// create a router instance
var router = new Router();

// ...add middleware here

// export the router to add it to your store
export default router;

Adding Middleware

There are 2 methods available to you for adding middleware to your application. While both are similar, they offer very different implementations of a similar concept.

The first method is .use(), which is often used for general middleware that should be invoked before proceeding. You can optionally provide a partial "path" as the first argument in order to require that the current URI begins with the given path.

The second method, .exact(), is for when you want a middleware or handler to fire only when the given path matches in full. Unlike .use(), the .exact() method requires that a path string be provided. This is typically going to be used for the final step of a route.

// add middleware that will be applied to all routes
router.use(function logger (ctx, next) {
  console.log("router -> " + ctx.location.href);
  next();
});

// add middleware that applies to a partial route name and redirects
// the user if the "token" value isn't set
router.use("/account", function isLoggedIn (ctx, next) {
  if ( ! localStorage.getItem("authToken")) {
    next(null, "/login");
  } else {
    next();
  }
});

// load up the home page
router.exact("/", handleHome);

// add a handler that dispatches actions based on route parameters
router.exact("/account/:page", function (ctx, next) {
  var page = ctx.params.page;
  // do something with the page name
});

What is Middleware?

If you have experience working with Connect or Express, then the middleware system in this library should feel pretty familiar. Middleware are functions that accept a context object (often shortened to ctx) that contains details about the current route and a callback function referred to as next.

Middleware is executed in the order that it is added to the router. When a middleware finishes execution, it should invoke the given next() method to call the next middleware function in the stack.

function middleware (ctx, next) {
  // when done, call next() to invoke the next middleware
  // in the current router's stack
  next();
}

Router Depth & Error Handling

Middleware "stacks" have depth, meaning, the next() call can only invoke sibling (or nested middleware) in its stack. When any non-falsey arguments are passed to next(), the sibling stack call is skipped and any parent next() callback is invoked with the given arguments instead.

What this means: If middleware has a problem and wants to quit execution of further middleware, then an Error should be thrown or passed as the first argument to next(). The "hoisting" function will then be handed the Error object and can handle it.

function errorMiddleware (ctx, next) {
  // did we have an error? tell `next()` about it
  next(new Error("something went wrong"));
}

Redirects using connectHistory()

When using the connectHistory() function in conjunction with a Router, you can optionally pass a URI as a second parameter to next() to invoke a redirect, provided that the first "error" argument is null.

function redirectMiddleware (ctx, next) {
  // perform a redirect by passing the desired URI as the second argument
  next(null, "/example");
}

The context Object

FieldTypeDescription
locationObjectThe location object provided by history when routing is initialized.
paramsObjectThe parsed URI tokens for the route when a path with tokens has been provided for the middleware or route handler. Example: if you had a handler bound to /greet/:name and the route was /greet/world, then this value would be { name: "world" }.
queryObjectA parsed version of the query string for the route. An example would be ?foo=bar being converted to { foo: "bar" }.
uriStringThe URI or location.pathname for the request.

Support for history

This library does not include its own tooling for handling location or history changes. Instead, we recommend you use the history library on NPM, which has become an industry standard. To make integration with this library (or libraries with a similar contract) easier, we provide the connectHistory() method.

This function subscribes your router to history changes and also kicks off the initial routing call on load. Additionally, this is the step where error handling and creation of context object occurs.

import createHistory from "history/createBrowserHistory";
import { connectHistory } from "@helpfulhuman/router-kit";
import router from "./router";

const history = createHistory();

connectHistory(router, history);

Custom Context and Error Handling

An optional third argument can be provided to connectHistory() in the event that you need more control of the context object and error handling.

Note: This removes the default error handling support for redirects, so make sure you handle that as needed.

connectHistory(router, history, function (context, runMiddleware) {
  runMiddleware(context, function (err, redirect) {
    // handle this in a custom manner
  });
});

Aliases

Aliases allow you to work with a semantic route name as an abstraction over the actual route's URI. By not littering URIs throughout your code, you can reduce the risk of forming bad URIs or reduce the hastle often associating with having to refactor URIs.

Note: You can use tokens in the path that you're aliasing.

// add a named alias for routing to a specific task
router.alias("viewTask", "/tasks/:taskId");

// route to the aliased URI -> /tasks/1000
router.buildUri("viewTask", { taskId: "1000" });
1.1.3

7 years ago

1.1.2

7 years ago

1.1.1

7 years ago

1.1.0

7 years ago

1.0.5

7 years ago

1.0.4

7 years ago

1.0.3

7 years ago

1.0.2

7 years ago

1.0.1

7 years ago

1.0.0

7 years ago