Skip to content
This repository has been archived by the owner on Nov 19, 2023. It is now read-only.

Sharing my toxy-based development proxy. #57

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
165 changes: 165 additions & 0 deletions examples/uiDeveloperNerdvana.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,165 @@
var toxy = require('..'); /** we have to use this line when running in toxy/examples.
use this elsewhere
# var toxy = require('toxy');
**/
var express = require('express');
var poisons = toxy.poisons;
var rules = toxy.rules;

// Create a new toxy proxy
var proxy = toxy();
//var Array = require('Array');

/**********

You probably want to change the dirs, apiRoots and host line.

*************/

var rootPath = __dirname; // start with local directory

var defaultBackend = 'yourbackendhost.com';
var apiRoots = ['/api','/login']; // URLs beginning with this are intercepted and routed to your backend.
var staticDirs = [rootPath, rootPath+ '/dist', rootPath+ '/build']; //
var host = process.env.HOST || defaultBackend;
var poisonrate = process.env.POISONRATE || 0;
var maxlatency = process.env.MAXLATENCY || 0;
var minlatency = process.env.MINLATENCY || maxlatency/2;
var throttle = process.env.THROTTLE || 0;


var app = express(),
port = process.env.PORT || 8000;

function processRequest(req,res,next) {
console.log(">>>>"+req.url);
next();
}

function applyPoisons(route)
{
if (poisonrate > 0)
{
route.poison(poisons.inject({
code: 503,
body: '{"error": "toxy injected error"}',
headers: {'Content-Type': 'application/json'}
}))
.withRule(rules.probability(poisonrate));
}
if (maxlatency > 0)
{
route.poison(poisons.latency({max:maxlatency, min: minlatency})).withRule(rules.method('GET'));
}
if (throttle > 0)
{
route.poison(poisons.bandwidth({bps: throttle})).withRule(rules.method('GET'));
}

}

function processResponse(req,res,next) {
console.log("<<<<<"+req.url);
var keys = Object.keys(res._headers),
len = keys.length,
prop,
value;
for (i=0; false && i < len;i++)
{
prop = keys[i];
value = res._headers[prop];
//console.log("replacing",prop,value);

/****
Most backend hosts give you a cookie that only works with their domain, by setting
Secure on the cookie.
***/
if (Array.isArray(value))
{
for (jx=0; jx < value.length; jx++)
{
v2 = value[jx];
value[jx] = v2.replace(/Secure/g,'');
}
}
else
{
value.replace(/Secure/g,'');
res._headers[prop]=value;
}
}

//res.connection.uncork() // needed to make rocky/toxy work with node 4.x
next()
}

// Default server to forward incoming traffic
/*** Change https to http if your API server isn't https****/
proxy
.forward('https://'+host)


for (var ix=0;ix< apiRoots.length;ix++)
{
var root = apiRoots[ix]+'/*';
console.log('proxying',root);
route=proxy
.all(root)
.withRule(rules.method(['POST', 'PUT', 'DELETE','GET']))
.options({ secure: false })
.use(processRequest)
.transformResponseBody(processResponse)
.host(host);
applyPoisons(route);
}


// Enable the admin HTTP server
var admin = toxy.admin({ cors: true })

// Add the toxy proxy instance
admin.manage(proxy)

admin.listen(9000)
console.log('Admin server listening on port:', 9000)

for (var dx=0; dx< staticDirs.length; dx++)
{
console.log("Serving static content from ", staticDirs[dx])
app.use(express.static(staticDirs[dx]));
}
app.use(proxy.middleware())
app.listen(port);

console.log("Environment Variables/Parameters are:");
console.log("HOST=",host);
console.log("PORT=",port);
if (poisonrate > 0)
console.log("POISONRATE=",poisonrate," % of time to reply with 5xx instead of data");
else
console.log("POISONRATE= 0");
console.log(" no poisoning of requests");

if (maxlatency > 0)
{
console.log("MAXLATENCY=",maxlatency, ' milliseconds');
console.log("MINLATENCY=",minlatency, ' milliseconds');
}
else
{
console.log("MAXLATENCY=",maxlatency);
console.log(" NOT adding latency set at least MAXLATENCY to enable");

}

if (throttle > 0)
{
console.log('THROTTLE=', throttle, ' bps');
}
else
{
console.log('THROTTLE=0 bps');
console.log(' no throttling will be performed');
}

console.log('Test it:', 'http://localhost:'+port+'/index.html')
58 changes: 58 additions & 0 deletions examples/uiDeveloperNerdvana.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
# What is UI Developer Nerdvana?

UI Developer Nerdvana is when your *code*-*build*-*test* cycle can be shortened to
*save*-*refresh*. From *minutes* to *seconds*. Once you have achieved nerdvana, it can be
very hard to go back to waiting for a lengthy *code*-*build*-*deploy*-*test* process.

`uiDeveloperNerdvana.js` is a sample for `toxy` to help you acheive nerdvana. What it does
is pretty simple. It looks at the requests coming in, and routes requests beginning with `/api`
or `/login` to the host of your choice.

In other words, if you're developing in JavaScript, TypeScript, or nearly any other modern
UI technology where the browser executes your UI code, and the backend code is served by
somewhere else, you can setup a common backend server for your UI team. Since the UI code
is executed by the browser anyways; there's no reason to deploy it anywhere. If you're using
`gulp` or `webpack`, you can use their `watch` features to automatically build. So *Save* becomes
your *Deploy*.

By changing the backend host, you can test against Production, or a particular QA persons
machine if they've setup a tricky to reproduce bug.

Nerdvana also implements some poisons for toxy that can be controlled from the command line.

## Ok, so how do I get started?

1. Copy this file to your UI project as `nerdvana.js`.
2. Add toxy to your package.json in devDependencies, and `npm install` or `yarn`.
3. Change `defaultBackend` in the code to match the backend host name you want to use.
4. Change `apiRoots` if you're using something other than `/api` or `/login` as your
API route in the backend.
5. If serving your front end content from something other than the current directory, or
`./build` or `./dist`, modify `staticDirs`.
6. Setup `watch` in your build system.
11. Launch the proxy with `node nerdvana.js`
7. Load your UI by going to the opening page.
8. Make a change and save it.
9. Refresh your browser.
10. *Do Victory Dance*


### Advanced Features & Options

Rather than parse a command line, nerdvana will read certain values from the environment
variables, which can be also set from the command line.

#### Repoint the proxy


Ex: `HOST=<new host> node nerdvana.js`. will use the specified host instead of the
defaultBackend value. Same thing with `PORT=`. This is very useful to point a production or
a special build of the backend.

#### Cause errors to make sure your UI is robust

`POISONRATE=25` will cause 25% of the API requests to return an error so you can make sure
your UI will work when people's network connection is unreliable.

`MAXLATENCY=5000` will cause each API call to take 2.5 to 5 seconds to complete, so you can
debug race conditions, and also see what its like when your user's network connection is slow.