npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

@labyrinthos/file-routes

v0.2.4

Published

Lightweight library for using file-based routing in AWS Lambda and Express.

Downloads

4

Readme

File Routes

Lightweight library for using file-based routing in AWS Lambda and Express.

Installation

npm i @labyrinthos/file-routes

Extra Request Properties

The follow props are added to both the Request object in express and the event in lambda.

| Property | Description | | --- | --- | | sourceRoute | The source route that was matched in the request. Will have the same format as the file names (minus the extesions) so that it is the same between both types of deployment.

Route Folder Structure

All routes should be in a single folder that will be passed into the initialization function. Only files ending with .js or .mjs will be imported and used as routes.

Any files starting with - will be ignored. Files or folders can take path params by using [variable name] in the file (or folder) name.

Wildcard routes can be made by putting + at the end of a parameter route inside the [] (ex: [path+].mjs).

Actions can be run in front of routes (think app.use in express) by defining a {actions}.mjs (or .js) in the folder. These actions will be run in top-down order (so /{actions}.mjs will go before /wat/{actions.mjs}). Actions can send data back early to bail out of a route call the same way a normal handler function would send a value. An actions file should have a default export with an array of funtions in the order to be called, and each function will have the same argument list as the handler functions, so requests can be modified by an action before being passed to the handler.

Action functions apply to every route in the same folder, and every folder under. To target specific routes with actions, you will need to check the path of a request and ignore any routes you dont want to trigger.

Note: If using .js in route file names, "type": "module" needs to be in the package.json file or the import will fail.

Pathing Note: If a relative path is passed to the function for loading routes, it will be relative to the current working directory (treat it as a file function, not as a specialized import).

Handler Function

The handler functions need to export whichever HTTP verbs they will respond to as objects with specific properties. The HTTP verb export should be all caps (GET/POST/HEAD/etc.).

| Property | Description | | --- | --- | | handler | The handler function for the route | description | A description of the route. Currently only supports basic strings (maybe markdown later?) | type | The type the handler function returns. Will eventually use for something cool on auto documentation. Probably use the same format as schema. | schema | Used when validating/masking the returned data. See @axel669/joker lib for details on schema validation.

both examples will generate handlers for the routes /thing, /:userID/info, and /overlay/:overlayID.

Handler & Response

file-routes abstracts away the response into a single API for both Lambda and Express, meaning code can be converted from one to the other with minimal effort.

The handler is given 2 arguments:

  1. The Lambda Event or Express Request
  2. The file-routes Response function

In order for a handler to return data, it must have a return value from the Response function provided (even in Express).

Response

The Response function has 2 call signatures:

  • Response(data)
  • Response(headers, data)

The data is whatever data is going to be return in its raw form (the provided extra types will convert it for sending). The headers is an object with the keys in http header form (i.e. Content-Type).

In order to set a custom status code for the response, use array access with the status code as the index (res[404], res[204], etc). The default status code is 200, except for the redirects which default to 301.

The default call (no type used) will attempt to use the @axel669/joker library to validate and mask the returned data, using the schema defined on the route. If no schema is defined and the default call is used it will return an error.

Response types:

  • .json: JSON data that isn't validated
  • .text: plain text response
  • .html: html text response
  • .raw: return raw data, using the headers to set the Content-Type
  • .redirect: redirect, uses the content argument as the url to redirect to
  • .base64: send base64 encoded data back from a Lambda function

In addition to the response types, the response object has its own set of funcs to perform response formatting tasks for parts that are not the return data.

  • .setCookie(name, value[, options]): See cookie.serialize for details on the options available to cookies

Examples

export const GET = {
    description: "Just returns some random data.",
    schema: {
        a: "int",
        wat: { text: "string" },
        c: { d: "string" },
    },
    handler: async (event, res) => {
        //  use validation and masking
        return res({
            a: 10,
            b: 12,
            wat: [
                { text: "woah" },
                { text: "first try!" }
            ],
            c: {
                d: "E",
                f: "g100",
                h: ["i", 9, "j"]
            }
        })
    }
}

export const POST = {
    handler: (event, res) => {
        if (Math.random() < 0.5) {
            //  json without validation/masking
            return res.json(
                { "X-Response": "Custom header!" },
                [1, 2, 3, 4]
            )
        }
        //  custom error code on text returned
        return res.text[404]("Not Found")
    }
}

export const PUT = {
    handler: (event, res) => {
        //  redirect
        res.redirect("https://google.com")
    }
}

Lambda Usage

API Gateway Setup

The APIG route that calls the lambda must use {path+} at the end so that the Lambda function can identify which route to look for in the handlers.

Lambda File Structure

lambda
│  index.mjs
│  package.json
├─ node_modules
├─ routes
│  │  thing.mjs
│  ├─ [userID]
│  │  │  -internal.mjs
│  │  │  info.mjs
│  ├─ overlay
│  │  │  [overlayID].js

Lambda Function

import lambdaService from "@labyrinthos/file-routes/lambda"

const service = await lambdaService("routes")

export async function handler(event) {
    return await service(event)
}

Express Usage

Express File Structure

project
│  server.mjs
│  package.json
├─ node_modules
├─ routes
│  │  thing.mjs
│  ├─ [userID]
│  │  │  -internal.mjs
│  │  │  info.mjs
│  ├─ overlay
│  │  │  [overlayID].js

server.mjs

The return value from initialization is an express.Router object.

import express from "express"

import fileRoutes from "@labyrinthos/file-routes/express"

const app = express()
const fileRouter = await fileRoutes("routes")

app.use(fileRouter)

//  Optionally put it under a route instead of the root of the routes
app.use("/api", fileRouter)