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

@ogre.dev/framework

v1.0.6

Published

Ogres are like onions... They have layers; TypeScript framework for Node.js

Downloads

8

Readme

The Ogre Framework

license downloads npm version codecov

Fast and minimalist framework for Node.js written in TypeScript.

Ogres are like onions... They have layers.

import Ogre from '@ogre.dev/framework";
const onion = new Ogre();

onion.addLayer((context, next) => {
  const { response } = context;

  response.setBody('What are you doing in my swamp!?');
});

onion.listen(3000);

Installation

The framework is available through an npm registry:

npm install @ogre.dev/framework

Onions and layers

Unlike most frameworks where middleware functions are called sequentially, the Ogre framework uses a layer system where the first layers in the stack wrap around the following layers, much like onions or Russian dolls.

A Layer takes a context and a reference to the next layer as arguments:

const layer: Layer = (context, next) => {
  ...
};

Whenever a layer calls its next parameter, the request lifecycle enters the next layer in the stack. Once the execution of the next layer has finished, the initial layer can proceed with the rest of its code.

Executing the following:

import Ogre from '@ogre.dev/framework';

const onion = new Ogre();

onion
  .addLayer((context, next) => {
    console.log('entering layer 0');
    next();
    console.log('exiting layer 0');
  })
  .addLayer((context, next) => {
    console.log('entering layer 1');
    next();
    console.log('exiting layer 1');
  })
  .addLayer((context, next) => {
    console.log('entering layer 2');
    console.log('exiting layer 2');
  };

onion.listen(3000);

...will print:

entering layer 0
entering layer 1
entering layer 2
exiting layer 2
exiting layer 1
exiting layer 0

Layers's next method can only be called once. Subsequent calls are ignored.

Note that layers can be asynchronous. When in doubt, it is advised to await the execution of the next layer.

A typical use case would be to record the time it took to respond to the request:

import Ogre from '@ogre.dev/framework';

const onion = new Ogre();

onion
  .addLayer(async (context, next) => {
    const tic = new Date().getTime();

    await next();

    const toc = new Date().getTime();

    console.log(`execution took ${toc - tic}ms`);
  })
  .addLayer(async () => new Promise((resolve) => setTimeout(resolve, 1000));
  });

onion.listen(3000);
execution took 1002ms

Routing

Routing overview

The Ogre framework adopts a REST approach to routing with the extendable Resource class to model HTTP resources.

For instance, let's consider the path /users/123 which targets the users HTTP resource with a specific userId of 123.

Here is how you would define a User resource with a simple GET handler:

import { Resource } from '@ogre.dev/framework';

class UserResource extends Resource {
  path = '/users/{userId}';

  get = (context) => {
    const { request, response } = context;

    response.setBody({ userId: request.pathParameters.userId });
  };
}

export default new UserResource().toLayer();

Note that the userId path variable is accessible through context.request.pathParameters.

You can then import the resource into your app and use it as a layer:

import User from './resources/User';

...

onion.addLayer(User);

...

Paths

As we have seen in the previous section, resources revolve around their paths.

The path property can be either a string or directly a regular expression. The former may contain path variables surrounded by brackets (e.g. {userId}) that are made accessible through context.request.pathParameters inside the resource layers, or an asterisk (e.g. /users/*) to match all paths starting with the pattern preceding the symbol.

For instance /users/{userId}/* will match /users/123, /users/my-user, /users/123/this/is/an/example etc.

Best practice

The example shown in the routing overview section is intentionally simple and is only intended to help new users get started.

For more advanced applications with many resources, it is best advised to follow a modular approach with a project structure similar to the following:

main.ts
/resources
  /Users
    index.ts
    /controllers
      get.ts
      post.ts
      index.ts
// /resources/Users/index.ts

import { Resource } from '@ogre.dev/framework';
import { get, post } from './controllers';

class Users extends Resource {
  constructor() {
    super('/users');
    this.get = get;
    this.post = post;
  }
}

export default new Users().toLayer();
// /resources/Users/controllers/get.ts

import { Layer } from '@ogre.dev/framework';

const get: Layer = (context) => {
  const { response } = context;

  response.setBody([/* list of users */]);
};

export default get;
// /resources/Users/controllers/index.ts

export { default as get } from './get';
export { default as post } from './post';
// main.ts

import Users from './resources/Users';

...

onion.addLayer(Users);

...

Fallback handler

You may override the fallback method of the Resource class with a custom layer to handle cases where the request path matched the resource's but no handlers were found for the requested HTTP method.

Error handling

The Ogre framework tries to remain as little opinionated as possible, instead leaving the user to decide what works best for their particular needs.

By default no error handling is configured. In most cases however, common errors such as 404 - Not Found and 500 - Internal Server Error should be dealt with. This can be achieved with the following:

// main.ts

import Ogre from '@ogre.dev/framework';
import Users from './resources/Users';

const onion = new Ogre();

onion
  .addLayer(async (context, next) => {
    try {
      await next();
    } catch (error) {
      // handle 500 errors
      const { response } = context;

      response
        .setStatus(HttpStatusCode.INTERNAL_SERVER_ERROR)
        .setBody({ message: HttpStatusReason.INTERNAL_SERVER_ERROR });
    }
  })
  .addLayer(Users)
  .addLayer((context) => {
    // handle 404 errors
    const { response } = context;

    response
      .setStatus(HttpStatusCode.NOT_FOUND)
      .setBody({ message: HttpStatusReason.NOT_FOUND});
  });

Not that the order of the layers is important. The Internal Server Error layer wraps the entire layer stack and catches unhandled errors while the Not Found layer acts as the center-most layer thus intercepting requests that have not been dealt with by previous layers.

Trivia

The Ogre framework is a reference to the Shrek movie and its scene about ogres having layers, much like the framework:

Shrek: Ogres are like onions.

Donkey: They stink?

Shrek: Yes... No!

Donkey: Oh, they make you cry.

Shrek: No.

Donkey: Oh, you leave 'em out in the sun, they get all brown, start sproutin' little white hairs.

Shrek: No! Layers. Onions have layers. Ogres have layers. Onions have layers. You get it? We both have layers.

The release of the Ogre framework also coincided with the 20th anniversary of the movie.

Documentation

Full documentation

Contact