docs: update docs for koa v2

update readme and request, response toJSON method

update readme

update readme

update readme

update readme

update readme

update readme

update docs

update doc

pretty readme

update docs

fix then callback
This commit is contained in:
pana 2015-11-25 11:51:14 +08:00 committed by Jonathan Ong
parent d134fff9e8
commit 1e38b13a94
7 changed files with 277 additions and 297 deletions

241
Readme.md
View file

@ -5,7 +5,7 @@
[![build status][travis-image]][travis-url]
[![Test coverage][coveralls-image]][coveralls-url]
Expressive HTTP middleware for node.js to make web applications and APIs more enjoyable to write. Koa's middleware stack flows in a stack-like manner, allowing you to perform actions downstream then filter and manipulate the response upstream. Koa's use of generators also greatly increases the readability and robustness of your application.
Expressive HTTP middleware framework for node.js to make web applications and APIs more enjoyable to write. Koa's middleware stack flows in a stack-like manner, allowing you to perform actions downstream then filter and manipulate the response upstream.
Only methods that are common to nearly all HTTP servers are integrated directly into Koa's small ~570 SLOC codebase. This
includes things like content negotiation, normalization of node inconsistencies, redirection, and a few others.
@ -13,12 +13,130 @@
Koa is not bundled with any middleware.
## Installation
Koa requires __node v4.0.0__ or higher for (partial) ES2015 support.
```
$ npm install koa
$ npm install koa@next
```
Koa requires __node v4.0.0__ or higher for (partial) ES2015 support.
## Hello koa
```js
const Koa = require('koa');
const app = new Koa();
// response
app.use(ctx => {
ctx.body = 'Hello Koa';
});
app.listen(3000);
```
## Getting started
- [Kick-Off-Koa](https://github.com/koajs/kick-off-koa) - An intro to koa via a set of self-guided workshops.
- [Workshop](https://github.com/koajs/workshop) - A workshop to learn the basics of koa, Express' spiritual successor.
- [Introduction Screencast](http://knowthen.com/episode-3-koajs-quickstart-guide/) - An introduction to installing and getting started with Koa
## Middleware
Koa is an middleware framework, it can take 3 different kind function as middleware:
* common function
* async function
* generatorFunction
Here we write an logger middleware with different function.
### Common function
```js
// Middleware normally take two parameters (ctx, next), ctx is the context for one request,
// next is an function that is invoked to execute the downstream middleware. It returns a Promise with a then function for running code after completion.
app.use((ctx, next) => {
const start = new Date;
return next().then(() => {
const ms = new Date - start;
console.log(`${ctx.method} ${ctx.url} - ${ms}ms`);
});
});
```
### ___async___ functions (Babel required)
```js
app.use(async (ctx, next) => {
const start = new Date;
await next();
const ms = new Date - start;
console.log(`${ctx.method} ${ctx.url} - ${ms}ms`);
});
```
### GeneratorFunction
To use generator functions, you must use a wrapper such as [co](https://github.com/tj/co) that is no longer supplied with Koa.
```js
app.use(co.wrap(function *(ctx, next){
const start = new Date;
yield next();
const ms = new Date - start;
console.log(`${ctx.method} ${ctx.url} - ${ms}ms`);
}));
```
### Old signature middleware (v1.x)
If you want to use old signature or be compatible with old middleware, you must use [koa-convert](https://github.com/gyson/koa-convert) to convert legacy generator middleware to promise middleware.
```js
const convert = require('koa-convert')
app.use(convert(function *(next){
const start = new Date;
yield next;
const ms = new Date - start;
console.log(`${this.method} ${this.url} - ${ms}ms`);
}));
```
## Babel setup
For Node 4.0 and Babel 6.0 you can setup like this
```bash
// install babel and required presets
$ npm install babel-core --save
$ npm install babel-preset-es2015-node5 --save
$ npm install babel-preset-stage-3 --save
```
```js
// set babel in entry file
require("babel-core/register")({
presets: ['es2015-node5', 'stage-3']
});
```
## Running tests
```
$ make test
```
## Authors
See [AUTHORS](AUTHORS).
## Community
@ -35,123 +153,6 @@ $ npm install koa
- [中文文档](https://github.com/turingou/koa-guide)
- __[#koajs]__ on freenode
## Getting started
- [Kick-Off-Koa](https://github.com/koajs/kick-off-koa) - An intro to koa via a set of self-guided workshops.
- [Workshop](https://github.com/koajs/workshop) - A workshop to learn the basics of koa, Express' spiritual successor.
- [Introduction Screencast](http://knowthen.com/episode-3-koajs-quickstart-guide/) - An introduction to installing and getting started with Koa
## Example
```js
const Koa = require('koa');
const app = new Koa();
// logger
app.use((ctx, next) => {
const start = new Date;
return next().then(() => {
const ms = new Date - start;
console.log(`${ctx.method} ${ctx.url} - ${ms}ms`);
});
});
// response
app.use(ctx => {
ctx.body = 'Hello World';
});
app.listen(3000);
```
## Example with ___async___ functions (Babel required)
```js
const Koa = require('koa');
const app = new Koa();
// logger
app.use(async (ctx, next) => {
const start = new Date;
await next();
const ms = new Date - start;
console.log(`${ctx.method} ${ctx.url} - ${ms}ms`);
});
// response
app.use(ctx => {
ctx.body = 'Hello World';
});
app.listen(3000);
```
## Example with generator
To use generator functions, you must use a wrapper such as [co](https://github.com/tj/co) that is no longer supplied with Koa.
```js
const Koa = require('koa');
const app = new Koa();
const co = require('co');
// logger
app.use(co.wrap(function *(ctx, next){
const start = new Date;
yield next();
const ms = new Date - start;
console.log(`${ctx.method} ${ctx.url} - ${ms}ms`);
}));
// response
app.use(ctx => {
ctx.body = 'Hello World';
});
app.listen(3000);
```
## Example with old signature
If you want to use old signature or be compatible with old middleware, you must use [koa-convert](https://github.com/gyson/koa-convert) to convert legacy generator middleware to promise middleware.
```js
const Koa = require('koa');
const app = new Koa();
const convert = require('koa-convert')
// logger
app.use(convert(function *(next){
const start = new Date;
yield next;
const ms = new Date - start;
console.log(`${this.method} ${this.url} - ${ms}ms`);
}));
// response
app.use(ctx => {
ctx.body = 'Hello World';
});
app.listen(3000);
```
## Running tests
```
$ make test
```
## Authors
See [AUTHORS](AUTHORS).
# License

View file

@ -1,90 +1,15 @@
# Installation
Koa is supported in all versions of [iojs](https://iojs.org) without any flags.
Koa requires __node v4.0.0__ or higher for (partial) ES2015 support.
To use Koa with node, you must be running __node 0.11.16__ or higher for generator and promise support, and must run node(1)
with the `--harmony-generators` or `--harmony` flag.
You can quickly install a supposed version of node/iojs with your favorite version manager:
You can quickly install a supposed version of node with your favorite version manager:
```bash
$ nvm install iojs
$ nvm install v4.0.0
$ npm i koa
$ node my-koa-app.js
```
# Application
A Koa application is an object containing an array of middleware generator functions
which are composed and executed in a stack-like manner upon request. Koa is similar to many
other middleware systems that you may have encountered such as Ruby's Rack, Connect, and so on -
however a key design decision was made to provide high level "sugar" at the otherwise low-level
middleware layer. This improves interoperability, robustness, and makes writing middleware much
more enjoyable.
This includes methods for common tasks like content-negotiation, cache freshness, proxy support, and redirection
among others. Despite supplying a reasonably large number of helpful methods Koa maintains a small footprint, as
no middleware are bundled.
The obligatory hello world application:
```js
const Koa = require('koa');
const app = new Koa();
app.use(function *(){
this.body = 'Hello World';
});
app.listen(3000);
```
## Cascading
Koa middleware cascade in a more traditional way as you may be used to with similar tools -
this was previously difficult to make user friendly with node's use of callbacks.
However with generators we can achieve "true" middleware. Contrasting Connect's implementation which
simply passes control through series of functions until one returns, Koa yields "downstream", then
control flows back "upstream".
The following example responds with "Hello World", however first the request flows through
the `x-response-time` and `logging` middleware to mark when the request started, then continue
to yield control through the response middleware. When a middleware invokes `yield next`
the function suspends and passes control to the next middleware defined. After there are no more
middleware to execute downstream, the stack will unwind and each middleware is resumed to perform
its upstream behaviour.
```js
const Koa = require('koa');
const app = new Koa();
// x-response-time
app.use(function *(next){
const start = new Date;
yield next;
const ms = new Date - start;
this.set('X-Response-Time', `${ms}ms`);
});
// logger
app.use(function *(next){
const start = new Date;
yield next;
const ms = new Date - start;
console.log(`${this.method} ${this.url} - ${ms}`);
});
// response
app.use(function *(){
this.body = 'Hello World';
});
app.listen(3000);
```
## Async Functions with Babel
To use `async` functions in Koa, we recommend using [babel's require hook](http://babeljs.io/docs/usage/require/).
@ -106,7 +31,79 @@ For example, in your `.babelrc` file, you should have:
}
```
Currently, you could also use the [stage-3 preset](http://babeljs.io/docs/plugins/preset-stage-3/).
You can also use the [stage-3 preset](http://babeljs.io/docs/plugins/preset-stage-3/) instead.
# Application
A Koa application is an object containing an array of middleware functions
which are composed and executed in a stack-like manner upon request. Koa is similar to many
other middleware systems that you may have encountered such as Ruby's Rack, Connect, and so on -
however a key design decision was made to provide high level "sugar" at the otherwise low-level
middleware layer. This improves interoperability, robustness, and makes writing middleware much
more enjoyable.
This includes methods for common tasks like content-negotiation, cache freshness, proxy support, and redirection
among others. Despite supplying a reasonably large number of helpful methods Koa maintains a small footprint, as
no middleware are bundled.
The obligatory hello world application:
```js
const Koa = require('koa');
const app = new Koa();
app.use(ctx => {
ctx.body = 'Hello World';
});
app.listen(3000);
```
## Cascading
Koa middleware cascade in a more traditional way as you may be used to with similar tools -
this was previously difficult to make user friendly with node's use of callbacks.
However with async functions we can achieve "true" middleware. Contrasting Connect's implementation which
simply passes control through series of functions until one returns, Koa invoke "downstream", then
control flows back "upstream".
The following example responds with "Hello World", however first the request flows through
the `x-response-time` and `logging` middleware to mark when the request started, then continue
to yield control through the response middleware. When a middleware invokes `next()`
the function suspends and passes control to the next middleware defined. After there are no more
middleware to execute downstream, the stack will unwind and each middleware is resumed to perform
its upstream behaviour.
```js
const Koa = require('koa');
const app = new Koa();
// x-response-time
app.use(async function (ctx, next){
const start = new Date;
await next();
const ms = new Date - start;
ctx.set('X-Response-Time', `${ms}ms`);
});
// logger
app.use(async function (ctx, next){
const start = new Date;
await next();
const ms = new Date - start;
console.log(`${ctx.method} ${ctx.url} - ${ms}`);
});
// response
app.use((ctx) => {
ctx.body = 'Hello World';
});
app.listen(3000);
```
## Settings

View file

@ -16,16 +16,10 @@
## Does Koa replace Connect?
No, just a different take on similar functionality
now that generators allow us to write code with less
now that async functions allow us to write code with less
callbacks. Connect is equally capable, and some may still prefer it,
it's up to what you prefer.
## Do generators decrease performance?
Barely - check out the benchmarks in our readme, the numbers
are more than fine, and there's no substitute for proper
horizontal scaling.
## Does Koa include routing?
No - out of the box Koa has no form of routing, however
@ -41,15 +35,15 @@
## What custom properties do the Koa objects have?
Koa uses its own custom objects: `this`, `this.request`, and `this.response`.
Koa uses its own custom objects: `ctx`, `ctx.request`, and `ctx.response`.
These objects abstract node's `req` and `res` objects with convenience methods and getters/setters.
Generally, properties added to these objects must obey the following rules:
- They must be either very commonly used and/or must do something useful
- If a property exists as a setter, then it will also exist as a getter, but not vice versa
Many of `this.request` and `this.response`'s properties are delegated to `this`.
Many of `ctx.request` and `ctx.response`'s properties are delegated to `ctx`.
If it's a getter/setter, then both the getter and the setter will strictly
correspond to either `this.request` or `this.response`.
correspond to either `ctx.request` or `ctx.response`.
Please think about these rules before suggesting additional properties.

View file

@ -1,51 +1,39 @@
# Guide
This guide covers Koa topics are not directly API related, such as best practices for writing middleware,
application structure suggestions.
This guide covers Koa topics that are not directly API related, such as best practices for writing middleware, application structure suggestions, here we use async function as middleware you can also you commonFunction or generatorFunction which will be a little different.
## Writing Middleware
Koa middleware are simple functions which return a `GeneratorFunction`, and accept another. When
the middleware is run by an "upstream" middleware, it must manually `yield` to the "downstream" middleware.
Koa middleware are simple functions which return a `MiddlewareFunction` with signature (ctx, next). When
the middleware is run by an "upstream" middleware, it must manually invoke `next()` to run the "downstream" middleware.
For example if you wanted to track how long it takes for a request to propagate through Koa by adding an
`X-Response-Time` header field the middleware would look like the following:
```js
function *responseTime(next) {
async function responseTime(ctx, next) {
const start = new Date;
yield next;
await next();
const ms = new Date - start;
this.set('X-Response-Time', `${ms}ms`);
ctx.set('X-Response-Time', `${ms}ms`);
}
app.use(responseTime);
```
Here's another way to write the same thing, inline:
```js
app.use(function *(next){
const start = new Date;
yield next;
const ms = new Date - start;
this.set('X-Response-Time', `${ms}ms`);
});
```
If you're a front-end developer you can think any code before `yield next;` as the "capture" phase,
while any code after is the "bubble" phase. This crude gif illustrates how ES6 generators allow us
If you're a front-end developer you can think any code before `next();` as the "capture" phase,
while any code after is the "bubble" phase. This crude gif illustrates how async function allow us
to properly utilize stack flow to implement request and response flows:
![koa middleware](/docs/middleware.gif)
1. Create a date to track duration
2. Yield control to the next middleware
2. Await control to the next middleware
3. Create another date to track response time
4. Yield control to the next middleware
5. Yield immediately since `contentLength` only works with responses
6. Yield upstream to Koa's noop middleware
4. Await control to the next middleware
5. Await immediately since `contentLength` only works with responses
6. Await upstream to Koa's noop middleware
7. Ignore setting the body unless the path is "/"
8. Set the response to "Hello World"
9. Ignore setting `Content-Length` when no body is present
@ -55,18 +43,18 @@ app.use(function *(next){
13. Hand off to Koa to handle the response
Note that the final middleware (step __6__) yields to what looks to be nothing - it's actually
yielding to a no-op generator within Koa. This is so that every middleware can conform with the
same API, and may be placed before or after others. If you removed `yield next;` from the furthest
Note that the final middleware (step __6__) await to what looks to be nothing - it's actually
yielding to a no-op promise within Koa. This is so that every middleware can conform with the
same API, and may be placed before or after others. If you removed `next();` from the furthest
"downstream" middleware everything would function appropriately, however it would no longer conform
to this behaviour.
For example this would be fine:
```js
app.use(function *response(){
app.use(async function response(ctx, next){
if ('/' != this.url) return;
this.body = 'Hello World';
ctx.body = 'Hello World';
});
```
@ -91,14 +79,14 @@ app.use(function *response(){
function logger(format) {
format = format || ':method ":url"';
return function *(next){
return async function (ctx, next){
const str = format
.replace(':method', this.method)
.replace(':url', this.url);
.replace(':method', ctx.method)
.replace(':url', ctx.url);
console.log(str);
yield next;
await next();
}
}
@ -112,121 +100,120 @@ app.use(logger(':method :url'));
```js
function logger(format) {
return function *logger(next){
return async function logger(ctx, next){
}
}
```
### Combining multiple middleware
### Combining multiple middleware with koa-compose
Sometimes you want to "compose" multiple middleware into a single middleware for easy re-use or exporting. To do so, you may chain them together with `.call(this, next)`s, then return another function that yields the chain.
Sometimes you want to "compose" multiple middleware into a single middleware for easy re-use or exporting. You can use [koa-compose](https://github.com/koajs/compose)
```js
function *random(next) {
const compose = require('koa-compose');
async function random(ctx, next) {
if ('/random' == this.path) {
this.body = Math.floor(Math.random()*10);
ctx.body = Math.floor(Math.random()*10);
} else {
yield next;
await next();
}
};
function *backwards(next) {
async function backwards(ctx, next) {
if ('/backwards' == this.path) {
this.body = 'sdrawkcab';
ctx.body = 'sdrawkcab';
} else {
yield next;
await next();
}
}
function *pi(next) {
async function pi(ctx, next) {
if ('/pi' == this.path) {
this.body = String(Math.PI);
ctx.body = String(Math.PI);
} else {
yield next;
await next();
}
}
function *all(next) {
yield random.call(this, backwards.call(this, pi.call(this, next)));
}
const all = compose([random, backwards, pi])
app.use(all);
```
This is exactly what [koa-compose](https://github.com/koajs/compose) does, which Koa internally uses to create and dispatch the middleware stack.
### Response Middleware
Middleware that decide to respond to a request and wish to bypass downstream middleware may
simply omit `yield next`. Typically this will be in routing middleware, but this can be performed by
simply omit `next()`. Typically this will be in routing middleware, but this can be performed by
any. For example the following will respond with "two", however all three are executed, giving the
downstream "three" middleware a chance to manipulate the response.
```js
app.use(function *(next){
app.use(async function (ctx, next){
console.log('>> one');
yield next;
await next();
console.log('<< one');
});
app.use(function *(next){
app.use(async function (ctx, next){
console.log('>> two');
this.body = 'two';
yield next;
ctx.body = 'two';
await next();
console.log('<< two');
});
app.use(function *(next){
app.use(async function (ctx, next){
console.log('>> three');
yield next;
await next();
console.log('<< three');
});
```
The following configuration omits `yield next` in the second middleware, and will still respond
The following configuration omits `next()` in the second middleware, and will still respond
with "two", however the third (and any other downstream middleware) will be ignored:
```js
app.use(function *(next){
app.use(async function (ctx, next){
console.log('>> one');
yield next;
await next();
console.log('<< one');
});
app.use(function *(next){
app.use(async function (ctx, next){
console.log('>> two');
this.body = 'two';
ctx.body = 'two';
console.log('<< two');
});
app.use(function *(next){
app.use(async function (ctx, next){
console.log('>> three');
yield next;
await next();
console.log('<< three');
});
```
When the furthest downstream middleware executes `yield next;` it's really yielding to a noop
When the furthest downstream middleware executes `next();`, it's really yielding to a noop
function, allowing the middleware to compose correctly anywhere in the stack.
## Async operations
The [Co](https://github.com/visionmedia/co) forms Koa's foundation for generator delegation, allowing
Async function and promise forms Koa's foundation, allowing
you to write non-blocking sequential code. For example this middleware reads the filenames from `./docs`,
and then reads the contents of each markdown file in parallel before assigning the body to the joint result.
```js
const fs = require('co-fs');
const fs = require('fs-promise');
app.use(function *(){
const paths = yield fs.readdir('docs');
app.use(async function (ctx, next){
const paths = await fs.readdir('docs');
const files = await Promise.all(paths.map(path => fs.readFile(`docs/${path}`, 'utf8')));
const files = yield paths.map(path => fs.readFile(`docs/${path}`, 'utf8'));
this.type = 'markdown';
this.body = files.join('');
ctx.type = 'markdown';
ctx.body = files.join('');
});
```

View file

@ -21,7 +21,7 @@ THIS DOCUMENT IS IN PROGRESS. THIS PARAGRAPH SHALL BE REMOVED WHEN THIS DOCUMENT
Thus, if you'd like to be closer to node.js and traditional node.js-style coding, you probably want to stick to Connect/Express or similar frameworks.
If you want to dive into the land of generators, use Koa.
If you want to get rid of callbacks, use Koa.
As result of this different philosophy is that traditional node.js "middleware", i.e. functions of the form `(req, res, next)`, are incompatible with Koa. Your application will essentially have to be rewritten from the ground, up.

View file

@ -11,6 +11,7 @@ const parse = require('parseurl');
const qs = require('querystring');
const typeis = require('type-is');
const fresh = require('fresh');
const only = require('only');
/**
* Prototype.
@ -618,10 +619,10 @@ module.exports = {
*/
toJSON() {
return {
method: this.method,
url: this.url,
header: this.header
};
return only(this, [
'method',
'url',
'header'
]);
}
};

View file

@ -15,9 +15,9 @@ const typeis = require('type-is').is;
const statuses = require('statuses');
const destroy = require('destroy');
const assert = require('assert');
const path = require('path');
const extname = require('path').extname;
const vary = require('vary');
const extname = path.extname;
const only = require('only');
/**
* Prototype.
@ -516,10 +516,10 @@ module.exports = {
*/
toJSON() {
return {
status: this.status,
message: this.message,
header: this.header
};
return only(this, [
'status',
'message',
'header'
]);
}
};