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

ravenwood

v2.0.0

Published

A pipeline-oriented and modular HTTP server

Downloads

10

Readme

Ravenwood

ravenwood is a pipeline-oriented, extremely modular, HTTP server tailored on standard compliance for nodejs.

NPM Summary NPM Downloads

Build Status Coverage Status

Features

  • Two-ways middlewares
  • Dependencies Injection

See the changelog and the API reference

Ravenwood is pipeline oriented, so requests are processed by a chain of middleware stages before reaching a final handler. Stages are operating both ways: on entry, before the final handler and on exit, after the final handler. This is because depending on the use case, various actions may need to be performed on either or both logical paths.

The middleware stages are organised as a stack so any middleware called on entry will also be called on exit, unless an exception bubbles up the pipeline.

                 ┌────────────┐   ┌────────────┐         ┌────────────┐   ┌────────────┐
                 │ Middleware │   │ Middleware │         │ Middleware │   │ Handler    │
                 │            │   │            │         │            │   │            │
 HTTP Request ─>─│ enter()    │─>─│ enter()    │─>─ ┄ ─>─│ enter()    │─>─│            │
                 │            │   │            │         │            │   │  handle()  │
HTTP Response ─<─│    leave() │─<─│    leave() │─<─ ┄ ─<─│    leave() │─<─│            │
                 │            │   │            │         │            │   │            │
                 └────────────┘   └────────────┘         └────────────┘   └────────────┘

Pipeline stages have a (string) type, which is use to determine where to place each stage along the chain define on the server. Stages that are not specifically typed will always be traversed first, even when no final handler was defined (leading to e.g. 404 or 405 responses).

Middlewares

Middlewares can be given either as plain object descriptors or as classes extending the Middleware class. Descriptors will be scaffolded into classes just as if given straight as such:

// Descriptor
{
	type:  "authentication",
	enter: () => {}, // The function to call on pipeline entry
	leave: () => {}, // The function to call on pipeline exit
}

// Class
class extends Middleware("authentication") {
	enter() {} // The method to call on pipeline entry
	leave() {} // The method to call on pipeline exit
}

Routes

Routes can be given either as plain object descriptors or as classes extending the Route class. Descriptors will be scaffolded into classes just as if given straight as such:

// Descriptor
{
	method:      "GET",
	path:        "/",
	middlewares: [middlewareDescriptor, middlewareClass], // Route-specific middlewares
	handle: () => {}, // The function to call as a final handler
}

// Class
class extends Route("GET", "/", middlewareDescriptor, middlewareClass) {
	handle() {} // The function to call as a final handler
}

Server

Servers is where middleware and routes building blocks are all tied together into a proper pipeline. A server is built from a piquouze container to handle dependencies injection, with names modified by the mapping function before registration on the container.

const server = new Server(container, options, mapping);

To use middleware types, it is required to first define all stages in order:

server.setPipeline("stageType1", "stageType2", "stageType3");

Shared middlewares can then be added to the server. They will be reordered according to the defined pipeline stage types:

server.addMiddleware(middlewareDescriptor, middlewareClass/*, ...*/);

Routes can also be added to the server:

server.addRoute(routeDescriptor, routeClass/*, ...*/);

Requests can then be served once the server is started:

server.start(hostname, port);

Servers can be started and stopped as many times as required, as long as a started server is not started again before being properly stopped and a stopped server being stopped again before being properly started.

Testing

Servers can be easily tested by injecting fake request and observing the responses:

server.inject(request).then((response) => {});

Request injection can also be used to implemented various middlewares requiring output from the server.

Error Handling

Basic servers automatically handle error cases for situations where HTTP statuses 404, 405, 500, 501 and 505 may apply. Error responses are very terse but this behaviour can be modified by overriding the server catch method:

class VerboseServer extends Server {
	catch(error) {
		return new Promise((resolve) => resolve(new Response(500, "Explanatory reason")));
	}
}

Dependencies Injection

Middleware and route functions are all injected with dependencies previously defined on the container. Middleware and route class constructors are injected as well.

Each time a request is handled, a new child container is built and the request object registered on it with the result of mapping the name "request". The list of defined HTTP methods for the request path is registered with the result of mapping the name "allowed".

Each time a middleware or route handle function return an instance (or an array of instances) of the DI.Factory or DI.Value class, the value(s) or factory(ies) will be transfered to the container so that they can be injected on later stages, including during the exit phase of the pipeline.