Skip to content

Commit

Permalink
documentation updates
Browse files Browse the repository at this point in the history
  • Loading branch information
pfrazee committed Mar 15, 2014
1 parent 7066023 commit 3d3ab32
Show file tree
Hide file tree
Showing 9 changed files with 216 additions and 26 deletions.
23 changes: 16 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ Local.js 0.6.2

## Overview

Local.js is an open-source security and IPC framework for socially-shareable Web plugins. It provides an Ajax interface for communicating interchangeably with javascript functions, parallel threads, and network peers. It also includes tools for managing and securing Web Workers, and for exchanging and querying against links.
Local.js is an open-source security and IPC framework for socially-shareable Web plugins. It provides an Ajax interface for communicating interchangeably with javascript functions, parallel threads, and network peers. It also includes tools for managing and securing Web Workers, for emitting and subscribing to Server-Sent Events, and for exchanging and querying against links.

### Examples

Expand Down Expand Up @@ -85,7 +85,7 @@ local.dispatch({
});
```

If you need to **stream the request**, create a `local.Request` object, then send it to `local.dispatch()`:
If you need to **stream the request**, create a [`local.Request`](http://httplocal.com/docs.html#docs/en/0.6.2/api/request.md) object, then send it to [`local.dispatch()`](http://httplocal.com/docs.html#docs/en/0.6.2/api/dispatch.md):

```javascript
var req = new local.Request({ method: 'POST', url: 'http://foo.com', Content_Type: 'text/plain' });
Expand Down Expand Up @@ -114,7 +114,7 @@ local.GET({ url: 'http://foo.com', stream: true })
}
```

Local.js includes a registry of content-type serializers and parsers which are auto-invoked on the 'end' events of requests and responses. By default, it ships with json and application/x-www-form-urlencoded, but you can register more with `local.contentTypes`.
Local.js includes a registry of content-type serializers and parsers which are auto-invoked on the 'end' events of requests and responses. By default, it ships with json and application/x-www-form-urlencoded, but you can register more with [`local.contentTypes`](http://httplocal.com/docs.html#docs/en/0.6.2/api/contenttypes.md).

If successful, the **`body` attribute will include the parsed object**. If parsing fails, or the content-type is not available, the `body` attribute will be a string. Note that server functions are fired when headers are received, and so must always wait for the 'end' event:

Expand All @@ -133,7 +133,7 @@ local.POST({ foo: 'bar' }, 'httpl://foobar') // will default content-type to jso
});
```

Local.js also includes a registry of header serializers and parsers which are auto-invoked on the dispatch events. By default, it ships with Link, Accept, and Via. In responses, the **parsed headers are placed in the `response.parsedHeaders` object** to avoid confusion:
Local.js also includes a registry of header serializers and parsers which are auto-invoked on dispatch - [`local.httpHeaders`](http://httplocal.com/docs.html#docs/en/0.6.2/api/httpheaders.md). By default, it ships with Link, Accept, and Via. In responses, the **parsed headers are placed in the `response.parsedHeaders` object** to avoid confusion:

```javascript
local.HEAD('http://foo.com').then(function(res) {
Expand All @@ -143,7 +143,7 @@ local.HEAD('http://foo.com').then(function(res) {
});
```

**To query the links**, use `local.queryLinks`:
**To query the links**, use [`local.queryLinks`](http://httplocal.com/docs.html#docs/en/0.6.2/api/querylinks.md):

```javascript
local.HEAD('http://foo.com').then(function(res) {
Expand All @@ -154,7 +154,7 @@ local.HEAD('http://foo.com').then(function(res) {
});
```

**To decide which content-type to respond with**, use `local.preferredType`:
**To decide which content-type to respond with**, use [`local.preferredType`](http://httplocal.com/docs.html#docs/en/0.6.2/api/preferredtypes.md):

```javascript
local.addServer('foobar', function(req, res) {
Expand Down Expand Up @@ -196,6 +196,14 @@ The core of Local.js is a message router which adds a new scheme, `httpl://`, fo

<img src="assets/docs-messaging-diagram.png" />

Further reading:

- [HTTPL: JSON encoded message streams with HTTP semantics](http://httplocal.com/docs.html#docs/en/0.6.2/httpl.md)
- [Hypermedia Indexing Protocol (Link Header Usage)](http://httplocal.com/docs.html#docs/en/0.6.2/linkheader.md)
- [In-Application Sandboxing with Web Workers](http://pfraze.github.io/2014/03/08/in-application-sandboxing-with-web-workers.html)
- [Communicating with Web-Workers using HTTP](http://pfraze.github.io/2014/03/08/communicating-with-web-workers-using-http.html)
- [Applying User-Agent Behaviors in Web Applications to Enable Runtime Extension](http://pfraze.github.io/2014/03/08/applying-user-agent-behaviors.html)

<br/>

## Getting Started
Expand All @@ -204,7 +212,7 @@ Download <a href="//github.com/pfraze/local">local.js or local.min.js from the r

### Getting Help

Contact <a href="//twitter.com/pfrazee">@pfrazee</a> or join #httplocal on freenode.
Contact <a href="//twitter.com/pfrazee">@pfrazee</a> or join #httpl on freenode.

### Feedback &amp; Bug Reporting

Expand All @@ -220,6 +228,7 @@ Thank you to the following third-party library authors:

- [**parseUri**](http://stevenlevithan.com/demo/parseuri/js/), Stephen Levithan
- [**UriTemplate**](https://github.com/fxa/uritemplate-js), Franz Antesberger
- [**Negotiator**](https://github.com/federomero/negotiator), Federico Romero, Isaac Z. Schlueter
- [**Prism**](https://github.com/LeaVerou/prism), Lea Verou
- [**Marked**](https://github.com/chjj/marked), Christopher Jeffrey

Expand Down
2 changes: 1 addition & 1 deletion assets/css/sitewide.css
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
body { color: #555; font-family: 'Roboto', sans-serif; font-weight: 300; }
pre, code { font-family: Consolas, "Courier New", monospace; color: #5E5E5E; }
pre, code { font-family: Consolas, "Courier New", monospace; color: #5E5E5E; background: #f5f2f0; }
a { color: #3184D6; }
p { margin: 13px 0 17px; }
blockquote { border-left: 5px solid #ddd; }
Expand Down
9 changes: 8 additions & 1 deletion docs.html
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@

<body>
<div id="nav">
<div id="logo" style="display: block"><span>HTTP</span>Local.js</div>
<div id="logo" style="display: block">Local.js</div>
<ul class="inline"><li><a target="_top" href="/">Home</a></li><li class="active"><a target="_top" href="/docs.html">Documentation</a></li><li><a target="_top" href="https://github.com/pfraze/local">Repo</a></li></ul>
</div>

Expand All @@ -25,6 +25,13 @@
<li><a href="#README.md">README</a></li>
<li><a href="#docs/en/0.6.2/todosoa.md">Tutorial</a></li>
<li><a href="#docs/en/0.6.2/example_mdviewer.md">Example</a></li>
<li><a href="#docs/en/0.6.2/httpl.md">HTTPL</a></li>
<li><a href="#docs/en/0.6.2/linkheader.md">Link Header</a></li>
<li class="divider"></li>
<li>&nbsp;</li>
<li><strong style="color: gray">Additional Libraries</strong></li>
<li class="divider"></li>
<li><a href="https://github.com/pfraze/servware" target="_blank">Servware Framework</a></li>
<li class="divider"></li>
<li>&nbsp;</li>
<li><strong style="color: gray">API Reference</strong></li>
Expand Down
2 changes: 1 addition & 1 deletion docs/en/0.6.2/api/server.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ MyServer.prototype.handleLocalRequest(req, res) {

## local.Server

### .handleHttpRequest( <small>request, response</small> ) <small>=> undefined</small>
### .handleLocalRequest( <small>request, response</small> ) <small>=> undefined</small>

Request handler, should be overridden by subtypes.

Expand Down
2 changes: 1 addition & 1 deletion docs/en/0.6.2/api/worker.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ Approximates standard `console.log`. Also supports:

- `server`: required function|local.Server

Sets the server function for handling requests from the pages.
Sets the server function for handling requests from the pages. The server is stored as `self.main`, which worker scripts may set directly.

---

Expand Down
83 changes: 83 additions & 0 deletions docs/en/0.6.2/httpl.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
HTTPL: JSON encoded message streams with HTTP semantics
=======================================================

---

HTTPL is used in Local.js to communicate over Browser messaging channels (postMessage, WebRTC DataChannels). The channels offer guarantees on order and delivery which are similar to that of TCP, while HTTPL provides stream multiplexing. For unordered channels, HTTPL supports head-of-line blocking.

Unlike HTTP, HTTPL is full-duplex, meaning the request and response can stream simultaneously.

JSON encoding was chosen over HTTP's format to take advantage of the browser's native JSON library. It's a larger message format (it includes more syntax and labeling) but it parses much faster than a JS routine for HTTP does.

---

### Message Types

The format consists of 4 kinds of request messages: the header, the body chunk, the end, and the close. They are:

```javascript
// header
{
sid: 1, // stream id
mid: (isReorderingMessages) ? 1 : undefined, // message id
method: 'POST', // request method
path: '/foo?k=v', // target resource
headers: {
accept: 'text/html',
'content-type': 'application/json',
host: 'myworker.js'
}
}
```

```javascript
// chunk
{ sid: 1, mid: (isReorderingMessages) ? ++midCounter : undefined, body: '{"foo":"bar"}' }
```

```javascript
// end
{ sid: 1, mid: (isReorderingMessages) ? ++midCounter : undefined, end: true }
```

```javascript
// close
{ sid: 1, mid: (isReorderingMessages) ? ++midCounter : undefined, close : true }
```

These messages can be combined together if the client chooses to buffer them, though at the time of this writing local.js hasn't implemented that process yet.

```javascript
{
sid: 1,
method: 'POST',
path: '/foo',
headers: {
accept: 'text/html',
'content-type': 'application/json',
host: 'myworker.js'
}
body: '{"foo":"bar"}',
end: true,
close: true
}
```

The `body` attribute on chunk messages are always strings in the native encoding of the given content-type. Multiple chunk messages can be issued to spread the content across the messages sequentially.

The difference between end and close messages are subtle, but important. An end message signals the end of the request, but not the transaction. The requester is still listening for response data. The close message then signals that the client has ceased listening to the response. Typically, the server sends the close message, with an exception being server-sent event-streams, which clients often close.

The response has the same four types of messages, but with slightly different semantics. Here are all four combined:

```javascript
{
sid: 1, // stream id
mid: (isReorderingMessages) ? midCounter++ : undefined, // message id
status: 200, // status code
reason: 'Ok', // short explanation of the response
headers: { 'content-type': 'text/html' },
body: '<h1>success</h1>',
end: true,
close: true
}
```
90 changes: 90 additions & 0 deletions docs/en/0.6.2/linkheader.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
Hypermedia Indexing Protocol
============================

---

Local.js uses the [Web Linking](http://tools.ietf.org/html/rfc5988) standard to export metadata about services in the form of links.

```javascript
local.dispatch({ method: 'HEAD', url: 'http://foobar.com' })
```
```text
> HEAD http://foobar.com HTTP/1.1
< HTTP/1.1 204 no content
< Link: <http://foobar.com>; rel="self service",
< <http://foobar.com/mail>; rel="collection"; id="mailboxes",
< <http://foobar.com/users>; rel="collection"; id="users"
```
```javascript
.then(function(res) {
local.queryLinks(res, { rel: 'collection' });
// => [
// { href: "http://foobar.com/mail", rel: "collection", id: "mailboxes" },
// { href: "http://foobar.com/users", rel: "collection", id: "users" }
// ]
});
```

---

### URI Templates

Servers can use [URI Templates](http://tools.ietf.org/html/rfc6570) in their exported links (with [fxa/uritemplate-js](https://github.com/fxa/uritemplate-js)).

```javascript
local.dispatch({ method: 'HEAD', url: 'http://foobar.com/users' })
```
```text
> HEAD http://foobar.com/users HTTP/1.1
< HTTP/1.1 204 no content
< Link: <http://foobar.com>; rel="up service via",
< <http://foobar.com/users{?fname,lname}>; rel="self collection"; id="users",
< <http://foobar.com/users/admin>; rel="item"; id="admin",
< <http://foobar.com/users/{id}>; rel="item"
```
```javascript
.then(function(res) {
var selfLink = local.web.queryLinks(res, { rel: 'self collection' })[0];
local.UriTemplate.parse(selfLink.href).expand({ fname: 'Bob', lname: 'Robertson' });
// => http://foobar.com/users?fname=Bob&lname=Robertson

var itemLinks = local.web.queryLinks(res, { rel: 'item' });
local.UriTemplate.parse(itemLinks[1].href).expand({ id: 'brobertson' });
// => http://foobar.com/users/brobertson
});
```

---

### Index Navigation

The [Agent](#docs/en/0.6.2/api/agent.md) follows queries by issuing HEAD requests, searching the links, and issuing subsequent HEAD requests based on matches. The navigations are followed "lazily," meaning that the HEAD requests are only sent when the application calls a dispatch function.

> Read about link headers in [[The Hypermedia Indexing Protocol]]
```javascript
local.agent('http://foobar.com')
.follow({ rel: 'collection', id: 'users' })
.follow({ rel: 'item', id: 'brobertson' })
.dispatch({ method: 'GET', headers: { accept: 'application/json' }})
```
```text
> HEAD http://foobar.com
< HTTP/1.1 204 no content
< Link: <http://foobar.com>; rel="self service",
< <http://foobar.com/mail>; rel="collection"; id="mailboxes",
< <http://foobar.com/users>; rel="collection"; id="users"
> HEAD http://foobar.com/users HTTP/1.1
< HTTP/1.1 204 no content
< Link: <http://foobar.com>; rel="up service via foobar.com/-service",
< <http://foobar.com/users/admin>; rel="item"; id="admin",
< <http://foobar.com/users/{id}>; rel="item"
> GET http://foobar.com/users/brobertson HTTP/1.1
< HTTP/1.1 200 ok
> Accept: application/json
< ...
```

Notice that the item navigation did not find a full match. The navigator first looks for an exact match, then for a match with all attributes either matching or present in the URI template. In this case, `{ rel: 'item', id: 'brobertson' }` matched with `<http://foobar.com/users/{id}>; rel="item"`.
22 changes: 11 additions & 11 deletions docs/en/0.6.2/todosoa.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
Tutorial: TodoSOA
=================

[<a href="http://grimwire.com/todosoa">Live Demo</a> | <a href="https://github.com/grimwire/todosoa">Source Code</a>]
[<a href="http://httplocal.com/todosoa">Live Demo</a> | <a href="https://github.com/pfraze/todosoa">Source Code</a>]

---

Expand Down Expand Up @@ -30,26 +30,26 @@ local.setDispatchWrapper(function(req, res, dispatch) {
// Dispatch the request, wait for a response, then log both
dispatch(req, res).always(console.log.bind(console, req));
});
local.spawnWorkerServer('js/view.js');
local.spawnWorkerServer('js/view.js', { domain: 'view.js' });
local.addServer('storage', new app.Store(name));
local.addServer('todo', new app.Host('httpl://storage', 'httpl://view.js'));
local.addServer('todo', new app.Todo('httpl://storage', 'httpl://view.js'));
var todoApi = local.agent('httpl://todo');
```

The dispatch wrapper is an optional middleware that is injected between `dispatch()` and delivery of the request. It's used here for logging.

<a href="#docs/api/setdispatchwrapper.md">&raquo; setDispatchWrapper()</a>
<a href="#docs/en/0.6.2/api/setdispatchwrapper.md">&raquo; setDispatchWrapper()</a>

The `view.js` worker will take a moment to initialize, but you can send requests to it immediately after `spawnWorkerServer` is called. Local.js will buffer the messages until the worker signals "ready."

<a href="#docs/api/managing_servers.md">&raquo; Managing Servers</a><br>
<a href="#docs/en/0.6.2/managing_servers.md">&raquo; Managing Servers</a><br>

Agents are like database cursors for Web APIs. They request links from their current location, query against the link keyvalues, and construct a new location URI from the top match.

<a href="#docs/api/agent.md">&raquo; agent()</a>
<a href="#docs/en/0.6.2/api/agent.md">&raquo; agent()</a>


### Todo Server
### app.Todo Server

```javascript
function Todo(storageUrl, viewUrl) {
Expand Down Expand Up @@ -131,7 +131,7 @@ However, the API is not an exact match and includes some key differences:
- Response headers with serializers will automatically serialize on `.writeHead()`.
- Content types with parsers will automatically deserialize `.body` on 'end'.

<a href="#docs/api/server.md">&raquo; Server</a>, <a href="#docs/api/httpHeaders.md">&raquo; httpHeaders</a>, <a href="#docs/api/contenttypes.md">&raquo; contentTypes</a>
<a href="#docs/en/0.6.2/api/server.md">&raquo; Server</a>, <a href="#docs/en/0.6.2/api/httpheaders.md">&raquo; httpHeaders</a>, <a href="#docs/en/0.6.2/api/contenttypes.md">&raquo; contentTypes</a>


### Sending Requests with Agents
Expand Down Expand Up @@ -186,7 +186,7 @@ The `lookupResource()` query will find the first link with a `rel` that *include
If you refer back to the Todo server's definition, you'll notice that the last entry is `{ href: '/{id}', rel: 'item' }`. This is an example of a templated link. To avoid bloating responses with full indexes, URI Templates can be used to act as "catchalls."

<a href="#docs/api/agent.md">&raquo; Agents</a>
<a href="#docs/en/0.6.2/api/agent.md">&raquo; Agents</a>


### Rendering HTML
Expand Down Expand Up @@ -227,7 +227,7 @@ this.storageApi.dispatch({ method: 'GET', query: query })

This code is made inefficient to illustrate the 'bundling' feature of promises: rather than send all the items in one request to be rendered, they are sent individually and combined into one promise. This is a common pattern for syncing multiple requests.

<a href="#docs/api/promises.md">&raquo; Promises</a>
<a href="#docs/en/0.6.2/api/promises.md">&raquo; Promises</a>

The view server runs in a Worker (also for illustrative purposes):

Expand Down Expand Up @@ -425,4 +425,4 @@ To review, TodoSOA uses 3 servers - one for app logic, one for data storage, and

Compared to some of the MVC approaches in Javascript, TodoSOA is not as simple or convenient. Local.js has very different goals than Backbone or Knockout. It is designed to decouple the application into components which can be changed at runtime by users. However, closed-development applications can still benefit of reusability and reconfigurability gained by message passing.

> A recommended addition since the writing of this tutorial is <a href="#docs/api/bindrequestevents.md">Request Events</a>, which offer a convenient alternative to event listening.
> A recommended addition since the writing of this tutorial is <a href="#docs/en/0.6.2/api/bindrequestevents.md">Request Events</a>, which offer a convenient alternative to event listening.
Loading

0 comments on commit 3d3ab32

Please sign in to comment.