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

ep-deconstruct-api

v2.0.0

Published

A desconstructed, extendable API framework, requiring the minimum of work to get things done

Downloads

3

Readme

deconstruct-api

A deconstructed, extendable API framework, minimising the amount of work to get things done

installation & usage

In your project folder:

  npm install --save deconstruct-api

In your start script:

  const dapi = require ( 'deconstruct-api' );
  
  dapi.loadRoutes ( path.resolve ( './my-routes' ), error => {
    if ( error ) {
      return console.error ( error );
    }
    
    dapi.start ( process.env.PORT );
  } );

routes

handler names

The route folder is expected to contain routes handlers, the names of which are directly derived from the path it should serve, as follows:

GET /path/to/{some}/resource/{id} => ~path~to~:some~resource~:id~get.js

(where some and id are path parameters)

handler modules

All handler modules should be curried (a good library to use is ramda.curry), and should accept three parameters:

  const R = require ( 'ramda' );
  
  module.exports = R.curry ( ( utils, req, res ) => {} );
req

The request parameter is mostly accessed for query variables (req.query), path parameters (req.params), and in the case of POST and PUT, the body (req.body).

utils

Utils provides a few handy utilities:

log

A handy console.log replacement that stringifies JSON with line breaks and indentation.

callback

Returns results & errors to the user by simply calling them back. This utility is called with the res parameter, and returns a callback function.

(See error utility for HTTP status codes)

  const R = require ( 'ramda' );
  
  module.exports = R.curry ( ( utils, req, res ) => {
    if ( ! is_auth ) {
        return utils.callback ( res )( {
            code: 401,
            message: 'Authentication required'
        } );
    }
    
    return utils.callback ( res )( {
        status: 'success'
    } );
  } );
error

Returns errors to the user by simply calling them back. This utility is called with the res parameter, and returns a callback function that can be called on any error. (Equivalent to calling utils.callback ( res )( error, null ))

If the error is an object, and has a numerical code attribute, the value of code is returned as the HTTP status code of the response. Otherwise, a status code of 500 will be returned.

  const R = require ( 'ramda' );
  
  module.exports = R.curry ( ( utils, req, res ) => {
    if ( ! is_auth ) {
        return utils.error ( res )( {
            code: 401,
            message: 'Authentication required'
        } );
    }
    
    return utils.callback ( res )( {
        status: 'success'
    } );
  } );
streamRoute

A utility to allow other routes to be re-used. It returns the result of route as a highland stream. As first parameter, it expects the name of the route you whish to reuse, and the remaining three parameters are utils, req, and res:

  const R = require ( 'ramda' );
  
  module.exports = R.curry ( ( utils, req, res ) => {
    utils.streamRoute ( '~some~:other~route~get.js', utils, req, res )
      .toCallback ( utils.callback ( res ) );
  } );

addUtil

The addUtil method can be used to add your own, custom utilities to the utils object that gets passed as the first argument to every handler. Only add utilities here that are completely ubiquitous (ie gets used by the majority of your handlers), or it will become bloated quite quickly.

example

   const H = require ( 'highland' );
   const R = require ( 'ramda' );
   const path = require ( 'path' );
   const cluster = require ( 'cluster' );
   const numCPUs = require ( 'os' ).cpus ().length;
   
   const deconstruct = require ( 'deconstruct-api' );
   
   const myUtil = someString => {
       return `transformed ${someString}`;
   };

   deconstruct.addUtil ( 'myUtil', myUtil ); // available as utils.myUtil ()

   if ( cluster.isMaster ) {
       console.log ( `MASTER: starting ${numCPUs} processes` );
       R.range ( 0, numCPUs ).forEach ( i => {
           console.log ( `MASTER: starting worker #${i}` );
           cluster.fork ();
       } );
   } else {
       return H.wrapCallback ( deconstruct.loadRoutes )( path.resolve ( './routes' ) )
           .errors ( error => {
               console.error ( error );
           } )
           .each ( routes => {
               console.log ( 'WORKER: started' );
               deconstruct.start ( process.env.PORT || 8080 );
           } );
   }

Windows support

In Windows the : character is not a valid character in file names, so alternatively the route files can use a different character (or string) e.g:

~path~to~__some~resource~__id~get.js

and then use loadRoutes like this:

  const dapi = require ( 'deconstruct-api' );
  
  dapi.loadRoutes ( {
    routeDir: path.resolve ( './my-routes' ), 
    pathParameterFlag: '__'
  }, error => {
    if ( error ) {
      return console.error ( error );
    }
    
    dapi.start ( process.env.PORT );
  } );