# Forward requests to another server

> Use PROXY() to map a URL prefix to an upstream server, choose how the path is copied, and $.proxy() to forward a single route.

Framework: total5
Product: Total.js 5 (total5@0.0.19)
Language: en
Content-SHA256: a5143999f45cb88cba286cb0dfca70e97c0f40c381830c2860aeb38043de9342
Snapshot: c0700e321579725c5cf4f5ace1ad7d2866d1b4f93c24a63c0b41b6b7998e976c
Sources: total5-installed@total5@0.0.19
Review: not-recorded

`PROXY(prefix, target)` forwards every request below a URL prefix to another server and streams the answer back, so one Total.js app can sit in front of several services. It runs before the routes, so a prefix handled by `PROXY()` never reaches `ROUTE()`. The request is passed on with its method, headers and body; the headers `x-forwarded-for`, `x-forwarded-url` and `x-forwarded-host` tell the upstream about the original request. `PROXY(prefix)` without a target removes the proxy.

The object it returns configures the proxy: `.copy(type)` chooses which part of the path is sent upstream (see below), `.timeout(ms)` limits the wait, `.check(fn)` makes the proxy apply only when `fn(ctrl)` returns true and `.before(uri, ctrl)` can change the outgoing request, for example to add a header.

`.copy()` takes `none` (the default), `extend` or `replace`. With **`none`** the upstream only receives the path of the target plus the query string: `/none/a/b/?q=1` becomes `/base/?q=1` for the target `http://host/base/`. With **`extend`** the rest of the request path is appended to the target path: `/extend/a/b/?q=1` becomes `/base/a/b/?q=1`, which is what you want for a gateway. `replace` behaves like `extend` when the target has a path of its own; when the target is just a host it sends the rest of the path **without the query string**, so prefer `extend`.

For a single route use `$.proxy(url)`: it sends the current request (method, query string, body and headers) to `url` and returns the upstream answer with its status code.

```js controllers/proxy.js
const Http = require('http');

// A small upstream server that reports what it received
Http.createServer(function(req, res) {
	res.writeHead(200, { 'content-type': 'application/json' });
	res.end(JSON.stringify({ method: req.method, url: req.url, token: req.headers['x-token'] || null, forwarded: !!req.headers['x-forwarded-url'] }));
}).listen(9411, '127.0.0.1');

// One proxy per copy mode, to see the difference (the target has the path /base/)
PROXY('/none/', 'http://127.0.0.1:9411/base/');
PROXY('/extend/', 'http://127.0.0.1:9411/base/').copy('extend');
PROXY('/plain/', 'http://127.0.0.1:9411/base/').copy('replace');

// Everything below /service/ goes to the upstream, and a header is added on the way
PROXY('/service/', 'http://127.0.0.1:9411/').copy('extend').before(function(uri, ctrl) {
	uri.headers['x-token'] = 'secret';
});

exports.install = function() {
	ROUTE('GET /single/', single);
};

function single($) {
	$.proxy('http://127.0.0.1:9411/from-route/');
}
```
