@stansom/usher

1.0.1 • Public • Published

USHER

A simple routing library for JavaScript browser and server-side, inspired by Clojure libraries.

There are two main functions for controlling your routes:

  • route(routesArray, request) is the async version of the route function
  • routeSync(routesArray, request) is the same function, but sync
  • routesArray is an array of routes objects,
    the objects are in the form:
{
   path: '/some/route/',
   methods?: {
       GET: ({ pathParams: params }) => ({
            status: 200,
            body: `Hi ${params.name}!`}),
       POST: (params) => ({
            status: 200,
            body: "The user has been added!"}),
   },
   response?: ({ pathParams: params }) =>
        <><h1>Hello from the browser</h1></>
}

Where:

  • path is a path as a string,
  • methods is an optional object, used mainly on the server side, it contains method name and function to respond.
    The methods can be: "GET", "POST", "PUT", "PATCH", "DELETE", "OPTIONS", "PATCH"
  • response is an optional function, it's commonly used for frontend.
  • pathParams that are passed to the response functions are extracted from a route based on a given path, for example:

    "/user/:name" extracts the :name from the "/user/john" route and passes it to the response function, so it can be used like this:

    (request) =>
      `Hello, user ${request.pathParams.name}. And welcome to the site.`;
    // returns "Hello, user john. And welcome to the site.

    "/user/:name/:surname?" where surname is an optional parameter, the route function will try to match it and if not will return the param with a null value.

    ({ pathParams: params }) => {
      return `Hello ${params.name}${
        params.surname ? ` with surname ${params.surname}` : "."
      }`;
    };
    // matching route "/name/jay/surname/rutanga"
    // returns "Hello jay with surname rutanga
    // matching route "/name/jay"
    // returns "Hello jay.

For the server-side it looks like this:

const routes = [
  {
    path: "/home/",
    methods: {
      GET: () => {
        return {
          status: 200,
          body: "Hello from the home route!",
        };
      },
    },
  },
  {
    path: "/user/:id",
    methods: {
      GET: ({ pathParams: { id } }) => {
        return {
          status: 200,
          body: `Hi user ${id}! How are you doing?`,
        };
      },
    },
  },
];

request is an object in that form:

const request = {
  path: "/home/",
  method: "GET",
};

You need to convert the Deno Request in this way:

function extractPathFromRequestURL(req: Request): string {
  const regex = /http\:\/\/.*\:\d+/gm;
  const replaced = req.url.replace(regex, "");
  return replaced;
}

function requestConverter(req: Request): IRequest {
  const url = extractPathFromRequestURL(req);

  return {
    method: req.method,
    url,
    body: req.body,
    headers: req.headers,
  };
}

Just call the route function with a routes array and a request object to get a response object
which can be used in any server, watch the node example for NodeJS in the examples directory.
These examples are also available:

async function handler(req: Request): Promise<Response> {
  const extractedReq = requestConverter(req);
  const routeResp = await route(routes, extractedReq);
  const resp = new Response(routeResp.body, { status: routeResp.status });

  return resp;
}
(function main() {
  Deno.serve({ port }, handler);
})();

// response is:
// {
//    status: 200,
//    body: "hello from the home route!",
// };

SUMMARY:

In summary, the route functions take an array of routes and a path object, and return the response when the paths are matched or { status: 404, body: "Not found" } object if there are no matched routes.
This means that you can return anything from the 'response' function and handle a request in a very flexible way.

Package Sidebar

Install

npm i @stansom/usher

Weekly Downloads

0

Version

1.0.1

License

MIT

Unpacked Size

25.9 kB

Total Files

16

Last publish

Collaborators

  • stansom