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

coiso

v1.0.0-beta.7

Published

Opinionated browser facing HTTP API template

Downloads

4

Readme

coiso

Versatile HTTP API template built out of a need to have predictable patterns when building HTTP services. It can be used both as a command line utility and a library.

Install

npm i --save coiso

Use

Create a resources folder in your project's root and enter it:

$ mkdir resources && cd resources

Then, create an index.js file and export a function that accepts the standard NodeJS HTTP handler signature:

module.exports = (req, res) => {
    res.end('Hello World!');
}

Next, add a start script in your package.json file:

{
    "scripts": {
        "start": "coiso"
    }
}

Finally, the server can be started like this:

$ npm start

You can now consume http://localhost:8080/.

From this moment on, you can create as many routes as you want, both Request/Response or WebSocket style.

CLI

coiso's command line interface wrap around it's API to provide a convenient scaffolding to help create projects faster and in a consistent fashion.

coiso expects to find one directory in the root of your project — resources.

Resources are Javascript modules whose the resources-relative path map to a HTTP route. If the file name ends in .ws.js it will be considered a WebSocket handler, otherwise it is a request handler.

  • A request handler exports a function thats receives unaltered NodeJS request and response objects as arguments.
module.exports = (req, res) => {
    res.end('Hello World!');
}
  • A WebSocket handler exports a function that receives unaltered websocket and NodeJS request objects as arguments.
module.exports = (ws, req) => {
    // Echo back the received messages
    ws.on('message', ws.send);
    
    // On connect
    ws.send('Hello websocket');
};

Both handler types receive an optional request context object as the third argument.

There are some simple rules for naming the files that define your routes:

  • The file resources/index.js corresponds to the root (/) of your app.
  • A file called resources/about.js corresponds to the /about route. resources/about/index.js is treated the same as resources/about.js.
  • A file called resources/blog/[slug].js corresponds to the /blog/:slug route in which case params.slug is available to the route via the request context object. This is called parametric routing.
  • A file called resources/[blog_name]/[slug].js corresponds to the /:blog_name/:slug route, in which case params.slug and params.blog_name are available to the route via the request context object. This is called multi-parametric routing.
  • Files and directories with a leading underscore do not create routes. This allows you to co-locate helper modules and components with the routes that depend on them — for example you could have a file called resources/_helpers/datetime.js and it would not create a /_helpers/datetime route

Configuration

coiso looks for a coisoconfig.toml file in the project root and if it finds one loads and transforms it to a plain javascript object for consumption. This file is split in 2 sections:

  1. core - coiso's own configuration directives
  2. the rest - your own configuration directives

Initialization

Frequently, APIs need to perform some tasks before they start accepting requests. For this purpose coiso looks into your module package.json main field, loads it and treats it as an async function with the signature:

module.exports = async function setup(server /*CoisoServer*/, config/*configuration object*/) {
    // Implement your logic here
}

Examples include:

  • load an in memory cache
  • fetch runtime configurations
  • execute an API call

If this function throws coiso will log the error and exit. If it succeeds, it moves on to setup the HTTP server and start accepting requests.

The return value of this function is ignored.

More Info

Run the help command to get to know what else the CLI offers:

$ npx coiso --help

Deploy to Production

Make sure you run through this checklist before deploying to production:

  • set environment variable NODE_ENV=production
  • set log level to a level higher than warn
  • run with node --abort-on-uncaught-exception

TODO

  • Codebase cleanup
  • ~~Add log support (pino, logpp)~~ (Done)
  • Unit tests
  • Integration tests
  • Improve documentation
  • http/2 support?
  • windows support?
  • ~~Server metrics~~ (performance hooks; can be done by an external library)
  • ~~cors support~~ (can be done as middleware)
  • ~~circuit breaker~~ (can be done as middleware)
  • ~~cluster support~~ (outside intended scope)
  • ~~websocket support?~~ (done)

Benchmarks

The bulk of time is spent in your application code rather than in coiso's code, so don't expect coiso to solve your performance problems. Nevertheless, coiso aims to be as lightweight as possible and performs similarly to a NodeJS raw HTTP server, latency-wise.

Synthetic Hello World Benchmark

This benchmark is not representative of a real world situation but it asserts the claims made above.

The test consists in a brief 15 seconds warmup:

$ echo "GET http://localhost:8080" | vegeta attack \
    -duration=15s \
    -rate 500 \
    -keepalive false \
    -timeout 0.3s \
    -workers 200 \
  | vegeta report

and then exercises the endpoint for 10 minutes at a rate of 1000 requests/seconds using 200 workers. A request is considered to timeout if it takes more than 100 milliseconds to reply. Keep-alive is disabled by default:

$ echo "GET http://localhost:8080/" | vegeta attack \
    -duration=600s \
    -rate 1000 \
    -keepalive false \
    -timeout 0.1s \
    -workers 200 \
  | vegeta report
Raw NodeJS Server (see file benchmark/raw-node-server.js)
   $ NODE_ENV=production node benchmark/raw-node-server.js

   Requests      [total, rate]            600000, 1000.06
   Duration      [total, attack, wait]    9m59.965012258s, 9m59.964663988s, 348.27µs
   Latencies     [mean, 50, 95, 99, max]  239.989µs, 206.255µs, 354.381µs, 555.784µs, 107.924215ms
   Bytes In      [total, mean]            7200000, 12.00
   Bytes Out     [total, mean]            0, 0.00
   Success       [ratio]                  100.00%
   Status Codes  [code:count]             200:600000
   Error Set:

coiso (see examples/hello-world)
   $ NODE_ENV=production npx coiso

   Requests      [total, rate]            600000, 1000.06
   Duration      [total, attack, wait]    9m59.964622632s, 9m59.96438675s, 235.882µs
   Latencies     [mean, 50, 95, 99, max]  270.008µs, 202.969µs, 472.339µs, 798.797µs, 87.146503ms
   Bytes In      [total, mean]            7200000, 12.00
   Bytes Out     [total, mean]            0, 0.00
   Success       [ratio]                  100.00%
   Status Codes  [code:count]             200:600000
   Error Set:

Frequently Asked Questions

Q: Why not ExpressJS or KoaJS?

A: Because I believe development time should be spent building business logic instead of focusing on details such as transport, logging, routing, etc. I strongly believe in repeatable patterns and love the idea to treat NFR's as a dependency as opposed to having to think about them everytime one builds something new.

coiso's opinionated filesystem layout was designed for companies that build and maintain HTTP API's as an everyday task. While not perfect, it scales well for a multi-team environment where ownership is spread amongst a large number of people.

In any case, ExpressJS and KoaJS (and many others) are exceptional tools to build HTTP API's.

Q: What does coiso offer?

A: coiso is just a wrapper around the raw NodeJS HTTP server. It makes opinionated decisions around libraries to handle common requirements such as routing, logging, url parsing, etc.... It's designed to be:

  • Easy: Designed for usage with async/await
  • Complete: Features initialization routine, logging, routing, websockets, webping and request body parsing
  • Agile: Built for easy development, easy deployment and containerization
  • Simple: Small and explicit API surface
  • Standard: Just HTTP. Optional lock in to the RequestContext object
  • Explicit: No middleware - modules declare all dependencies
  • Operations-friendly: Open to metric agents and designed with post-mortem analysis in mind

Prior Art

All inspired this package:

License

MIT