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

simple-proxy-gateway

v1.0.1

Published

This app is meant to be a very simple proxy gateway for API's, that is run alongside another node app or micro-service(s).

Downloads

2

Readme

Simple Proxy Gateway

This app is meant to be a very simple proxy gateway for API's, that is run alongside another node app or micro-service(s).

Requirements

  • NodeJS 6.x
  • Redis
  • Your own API's from somewhere

Getting Started

To get the app up and running quick:

Using Docker Compose

  1. Clone this repo
  2. Run docker-compose up
  3. Visit http://localhost:3000/posts?apikey=LeCxzc9yRJoBRBgpGjNCsqCaVdNNiQdezNwGcNEp

Running it like a normal NodeJS app

  1. npm install simple-proxy-gateway --save
  2. Start up a Redis server and point the app to it (see Env. Vars section below for more information). Or, for testing real quick: docker run -p 6379:6379 redis.
  3. Configure the app via env vars or provide a config with your site info (See below for more on the config section).

Sample App:

var Gateway = require('simple-proxy-gateway');

var gateway = new Gateway(require('./config'));
var port = process.env.PORT || 8001;

gateway.start(port, () => {
	logger.info('Gateway listening on port ' + port);
});
  1. node .

Configuration

There are two ways to configure the gateway: 1) Via a config file or 2) Via ENV vars.

Config File

sites: An array of sites the gateway will proxy

Sample site configuration (You can look at the config.js sample file in this repo as well):

{
	/**
	 * Express route to expose on the gateway for this site.
	 * The example below will allow any endpoint after `/`. e.g. `/posts`
	 */
	route: '/*',
	/**
	 * The site name.  This is checked against the consumer's access to a site.
	 */
	site: 'jsonplaceholder.typicode.com',
	/**
	 * The target server that the gateway is proxying.
	 */
	upstreamUrl: 'https://jsonplaceholder.typicode.com',
	/**
	 * The options for the gateway proxy.  This app uses the `express-http-proxy` module and will pass these options to this module.
	 */
	options: {
		https: true
	},
	/**
	 * The authentication plugin and options to assign to this site.
	 * Auth plugins can be found in the /auth folder
	 */
	auth: {
		type: 'apikey',
	},
	/**
	 * List of middleware plugins to apply to this site.  Plugins can be found
	 * in the /plugins folder
	 */
	plugins: [
		{ type: 'siteAccess' },
		{ type: 'rateLimit', lookup: 'user.apikey' }
	]
}

consumers: An array of consumers the gateway will allow through

Sample consumer:

{
	/**
	 * Consumer name
	 */
	name: 'some-app-from-somebody',
	/**
	 * API key used by this consumer (used by the apikey auth plugin)
	 */
	apikey: '123456789abcdefghijklmnop',
	/**
	 * Rate limit settings for this consumer (used by the rateLimit plugin)
	 */
	rateLimit: {
		total: 10000000,
		expire: 1000 * 600 * 60,
	},
	/**
	 * The site name this consumer can access.  Used by the siteAccess plugin
	 * to check against the site name to see if this consumer can hit the site.
	 */
	site: 'jsonplaceholder.typicode.com'
}

Environment Variables

You can also configure the gateway to proxy / secure one site using env vars:

  • PORT: The port on which the gateway runs
  • REDIS_HOST: Hostname of the redis server
  • REDIS_PORT: The redis port the server runs on
  • SITE_NAME: The site name
  • SITE_ENDPOINT_PATH: The express route / path to expose on the gateway. e.g. /* to catch everything.
  • SITE_UPSTREAM_URL: The upstream site the gateway is proxying
  • SITE_HTTPS: Use https for the proxy
  • SITE_AUTH_TYPE: The auth plugin to use. e.g. apikey
  • SITE_CONSUMER_APIKEY: The apikey of the consumer (if using the apikey plugin)
  • SITE_IS_RATE_LIMITED: Enable rate limiting
  • SITE_RATE_LIMIT_TOTAL: Total number of requests allowed
  • SITE_RATE_LIMIT_EXPIRATION: Timeframe in which number of requests are allowed
  • SITE_PLUGINS: Plugins to enable for the site. e.g. rateLimit, siteAccess
  • SITE_PLUGINS_RATE_LIMIT_LOOKUP: Path in the Express request object to compare to enforce the rate limit. e.g. user.apikey

Using a custom plugin

In a plugin's configuration (inside the site config), you can tell the gateway where your custom module is using the modulePath property:

// This object also gets passed to your custom plugin, for configuration
{
	type: 'mycustomplugin',
	modulePath: 'PATH_TO_PLUGIN_FOLDER/mycustomplugin',
	someParam: true,
	someOtherParam: '123456789'
}

Writing plugins

Authentication plugins are found in the auth folder, site plugins are found in the plugins folder.

All plugins must follow the following conventions:

  • The file name should be the name of the plugin. e.g. apikey.js means the name used in the config to select this plugin is apikey.
  • The plugin should export a ES6 class
  • The plugin should have a middleware method which returns an Express middleware function.

See below for example of the API key auth plugin:

var logger = require('winston');

class APIKeyAuthPlugin {
	constructor(config, server) {
		this.config = config;
	}

	middleware (site) {
		var consumers = this.config.consumers;

		return (req, res, next) => {
			var apiKey = req.headers.apikey || req.query.apikey;
			var consumer = consumers.filter(consumer => consumer.apikey && consumer.apikey === apiKey);

			// Make sure there is a consumer
			if (consumer.length < 1) {
				res.status(401).send({
					message: 'Unauthorized'
				});
				logger.log('debug', 'Unauthorized', apiKey);
				return;
			} else {
				req.user = consumer[0];
			}

			return next();
		};
	}
}

module.exports = APIKeyAuthPlugin;

See below for example of the rate limiting plugin:

var logger = require('winston');

class RateLimitPlugin {
	constructor(config, pluginConfig, server) {
		this.config = config;
		this.pluginConfig = pluginConfig;
		this.limiter = require('express-limiter')(server.app, server.db);
	}

	middleware (site) {
		var lookup = process.env.SITE_PLUGINS_RATE_LIMIT_LOOKUP || this.pluginConfig.lookup;

		return this.limiter({
			method: 'all',
			lookup: function (req, res, opts, next) {
				var user = req.user;

				opts.lookup = lookup || 'user.apikey';
				opts.total = user.rateLimit.total;
				opts.expire = user.rateLimit.expire;

				return next();
			},
			onRateLimited: function (req, res) {
				res.status(429).send({
					message: 'Rate limit exceeded'
				});
				logger.log('debug', 'Rate limit exceeded', req.user);
			}
		});
	}
}

module.exports = RateLimitPlugin;