README.md
[![build status](https://img.shields.io/travis/mjackson/mach.svg?style=flat-square)](https://travis-ci.org/mjackson/mach)
[![npm package](https://img.shields.io/npm/v/mach.svg?style=flat-square)](https://www.npmjs.org/package/mach)
[Mach](https://github.com/mjackson/mach) is an HTTP server and client library that runs in both node.js and the browser. It has the following goals:
* Simplicity: straightforward mapping of HTTP requests to JavaScript function calls
* Asynchronous: responses can be deferred using Promises/A+ promises
* Streaming: request and response bodies can be streamed
* Composability: middleware composes easily using promises
* Robustness: promises propagate errors up the call stack, simplifying error handling
### Servers
Writing a "Hello world" HTTP server in Mach is simple.
```js
var mach = require('mach');
mach.serve(function (conn) {
return "Hello world!";
});
```
All mach applications receive a single argument: a [Connection](https://github.com/mjackson/mach/blob/master/modules/Connection.js) object. This object contains information about both the request and the response, as well as metadata including the `method` used in the request, the [location](https://github.com/mjackson/mach/blob/master/modules/Location.js) of the request, the `status` of the response, and some helper methods.
Applications can send responses asynchronously using JavaScript promises. Simply return a promise from your app that resolves when the response is ready.
```js
var app = mach.stack();
app.use(mach.logger);
app.get('/users/:id', function (conn) {
var id = conn.params.id;
return getUser(id).then(function (user) {
conn.json(200, user);
});
});
```
The call to `app.use` above illustrates how middleware is used to compose applications. Mach ships with the following middleware:
- [`mach.basicAuth`](https://github.com/mjackson/mach/blob/master/modules/middleware/basicAuth.js): Provides authentication using [HTTP Basic auth](http://en.wikipedia.org/wiki/Basic_access_authentication)
- [`mach.catch`](https://github.com/mjackson/mach/blob/master/modules/middleware/catch.js): Error handling at any position in the stack
- [`mach.charset`](https://github.com/mjackson/mach/blob/master/modules/middleware/charset.js): Provides a default [charset](http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.17) in responses
- [`mach.contentType`](https://github.com/mjackson/mach/blob/master/modules/middleware/contentType.js): Provides a default [`Content-Type`](http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.17)
- [`mach.favicon`](https://github.com/mjackson/mach/blob/master/modules/middleware/favicon.js): Handles requests for `/favicon.ico`
- [`mach.file`](https://github.com/mjackson/mach/blob/master/modules/middleware/file.js): Efficiently serves static files
- [`mach.gzip`](https://github.com/mjackson/mach/blob/master/modules/middleware/gzip.js): [Gzip](http://en.wikipedia.org/wiki/Gzip)-encodes response content for clients that `Accept: gzip`
- [`mach.logger`](https://github.com/mjackson/mach/blob/master/modules/middleware/logger.js): Logs HTTP requests to the console
- [`mach.mapper`](https://github.com/mjackson/mach/blob/master/modules/middleware/mapper.js): Provides virtual host mapping, similar to [Apache's Virtual Hosts](http://httpd.apache.org/docs/2.2/vhosts/) or [nginx server blocks](http://nginx.org/en/docs/http/ngx_http_core_module.html#server)
- [`mach.methodOverride`](https://github.com/mjackson/mach/blob/master/modules/middleware/methodOverride.js): Overrides the HTTP method used in the request, for clients (like HTML forms) that don't support methods other than `GET` and `POST`
- [`mach.modified`](https://github.com/mjackson/mach/blob/master/modules/middleware/modified.js): HTTP caching using [`Last-Modified`](http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.29) and [`ETag`](http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.19)
- [`mach.params`](https://github.com/mjackson/mach/blob/master/modules/middleware/params.js): Multipart request parsing and handling
- [`mach.proxy`](https://github.com/mjackson/mach/blob/master/modules/middleware/proxy.js): Proxy request through to an alternate location
- [`mach.rewrite`](https://github.com/mjackson/mach/blob/master/modules/middleware/rewrite.js): Rewrites request URLs on the fly, similar to [Apache's mod_rewrite](http://httpd.apache.org/docs/current/mod/mod_rewrite.html)
- [`mach.router`](https://github.com/mjackson/mach/blob/master/modules/middleware/router.js): Request routing (ala [Sinatra](http://www.sinatrarb.com/)) based on the URL pathname
- [`mach.session`](https://github.com/mjackson/mach/blob/master/modules/middleware/session.js): HTTP sessions with pluggable storage including [memory](https://github.com/mjackson/mach/blob/master/modules/middleware/session/MemoryStore.js) (for development and testing), [cookies](https://github.com/mjackson/mach/blob/master/modules/middleware/session/CookieStore.js), and [Redis](https://github.com/mjackson/mach/blob/master/modules/middleware/session/RedisStore.js)
- [`mach.stack`](https://github.com/mjackson/mach/blob/master/modules/middleware/stack.js): Provides a `use` mechanism for composing applications fronted by middleware
- [`mach.token`](https://github.com/mjackson/mach/blob/master/modules/middleware/token.js): Cross-site request forgery protection
Please check out the source of a middleware file for detailed documentation on how to use it.
### Clients
Writing an HTTP client is similarly straightforward.
```js
var mach = require('mach');
mach.get('http://twitter.com').then(function (conn) {
console.log(conn.status, conn.response.headers, conn.responseText);
});
```
By default client responses are buffered and stored in the `responseText` connection variable for convenience. However, if you'd like to access the raw stream of binary data in the response, you can use the `binary` flag.
```js
var fs = require('fs');
mach.get({
url: 'http://twitter.com',
binary: true
}).then(function (conn) {
conn.responseText; // undefined
conn.response.content.pipe(fs.createWriteStream('twitter.html'));
});
```
### Proxies
Because all Mach applications share the same signature, it's easy to combine them in interesting ways. Mach's HTTP proxy implementation illustrates this beautifully: a proxy is simply an application that forwards the request somewhere else.
```js
var proxyApp = mach.createProxy('http://twitter.com');
// In a server environment we can use the mach.proxy middleware
// to proxy all requests to the proxy's location.
app.use(mach.proxy, proxyApp);
// In a client application we can call the proxy directly to
// send a request to the proxy's location.
mach.post(proxyApp, {
params: {
username: 'mjackson'
}
});
```
### Installation
Using [npm](https://www.npmjs.org/):
$ npm install mach
Or, include [`lib/umd/mach.min.js`](https://github.com/mjackson/mach/blob/master/lib/umd/mach.min.js) in a `<script>` tag:
```html
<script src="mach.min.js"></script>
```
### Issues
Please file issues on the [issue tracker on GitHub](https://github.com/mjackson/mach/issues).
### Tests
To run the tests in node:
$ npm install
$ npm test
The Redis session store tests rely on Redis to run successfully. By default they are skipped, but if you want to run them fire up a Redis server on the default host and port and set the `$WITH_REDIS` environment variable.
$ WITH_REDIS=1 npm test
To run the tests in Chrome:
$ npm install
$ npm run test-browser
### Influences
* [Strata](http://stratajs.org/)
* [Q-HTTP](https://github.com/kriskowal/q-http)
* [JSGI & Jack](http://jackjs.org/)
* [node.js](http://nodejs.org/)
### License
[MIT](http://opensource.org/licenses/MIT)