diff --git a/README.md b/README.md
index 560cb4b..6e2664e 100644
--- a/README.md
+++ b/README.md
@@ -15,82 +15,98 @@ _**Micro —** Async ES6 HTTP microservices_
* **Simple**. Oriented for single purpose modules (function).
* **Explicit**. No middleware. Modules declare all dependencies.
* **Standard**. Just HTTP!
-* **Lightweight**. The package is small and the `async` transpilation fast and transparent
+* **Lightweight**. The package is small and the `async` transpilation is fast and transparent
-## Example
-
-The following example `sleep.js` will wait before responding (without blocking!)
+## Usage
-```js
-const {send} = require('micro')
-const sleep = require('then-sleep')
+Install it:
-module.exports = async function (req, res) {
- await sleep(500)
- send(res, 200, 'Ready!')
-}
+```
+npm install --save micro
```
-To run the microservice on port `3000`, use the `micro` command:
+Add a script to your `package.json` like this:
```bash
micro sleep.js
```
-To run the microservice on port `3000` and localhost instead of listening on every interface, use the `micro` command:
-
-```bash
-micro -H localhost sleep.js
+```json
+{
+ "main": "index.js",
+ "scripts": {
+ "start": "micro -p 3000"
+ }
+}
```
-## Usage
+After that, we have to create an `index.js` file
-Install the package (requires at least Node v6):
+Populate `./index.js` inside your project:
```js
-npm install --save micro
+module.exports = function (req, res) {
+ return 'Welcome to micro'
+}
```
-And start using it in your `package.json` file:
+and then just run `npm run start` and go to http://localhost:3000
+
+So far, we have written a web server that sends 'Welcome to micro'
+
+### Async / Await
+
+
+ Examples
+
+
+
+Micro is built for usage with async/await. You can read more about async / await [here](https://zeit.co/blog/async-and-await)
```js
-"main": "index.js",
-"scripts": {
- "start": "micro"
+const sleep = require('then-sleep')
+
+module.exports = async function (req, res) {
+ await sleep(500)
+ return 'Ready!'
}
```
-Then write your `index.js` (see above for an example).
+#### Transpilation
-After that, you can make the server run by executing the following command:
+We use [is-async-supported](https://github.com/timneutkens/is-async-supported) combined with [async-to-gen](https://github.com/leebyron/async-to-gen),
+so that the we only convert `async` and `await` to generators when needed.
-```bash
-npm start
-```
+If you want to do it manually, you can! `micro(1)` is idempotent and
+should not interfere.
+
+`micro` exclusively supports Node 6+ to avoid a big transpilation
+pipeline. `async-to-gen` is fast and can be distributed with
+the main `micro` package due to its small size.
-### API
+### Body parsing
-#### micro
-**`micro(fn)`**
+
+ Examples
+
+
-- This function is exposed as the `default` export.
-- Use `require('micro')`.
-- Returns a [`http.Server`](https://nodejs.org/dist/latest-v4.x/docs/api/http.html#http_class_http_server) that uses the provided `fn` as the request handler.
-- The supplied function is run with `await`. It can be `async`!
-- Example:
-
- ```js
- const micro = require('micro');
- const sleep = require('then-sleep');
- const srv = micro(async function (req, res) {
- await sleep(500);
- res.writeHead(200);
- res.end('woot');
- });
- srv.listen(3000);
- ```
-
-#### json
+For parsing the incoming request body we included an async function `json`
+
+```js
+const { json } = require('micro')
+
+module.exports = async function (req, res) {
+ const data = await json(req)
+ console.log(data.price)
+ return ''
+}
+```
+
+#### API
**`json(req, { limit = '1mb' })`**
@@ -100,18 +116,23 @@ npm start
- Can be called multiple times, as it caches the raw request body the first time.
- `limit` is how much data is aggregated before parsing at max. Otherwise, an `Error` is thrown with `statusCode` set to `413` (see [Error Handling](#error-handling)). It can be a `Number` of bytes or [a string](https://www.npmjs.com/package/bytes) like `'1mb'`.
- If JSON parsing fails, an `Error` is thrown with `statusCode` set to `400` (see [Error Handling](#error-handling))
-- Example:
-
- ```js
- const { json, send } = require('micro');
- module.exports = async function (req, res) {
- const data = await json(req);
- console.log(data.price);
- send(res, 200);
- }
- ```
-#### send
+For other types of data check the [examples](#body-parsing-examples)
+
+### Sending a different status code
+
+So far we have used `return` to send data to the client. `return 'Hello World'` is the equivalent of `send(res, 200, 'Hello World')`.
+
+```js
+const { send } = require('micro')
+module.exports = async function (req, res) {
+ const statusCode = 400
+ const data = { error: 'Custom error message' }
+ send(res, statusCode, data)
+}
+```
+
+#### API
**`send(res, statusCode, data = null)`**
@@ -123,62 +144,31 @@ npm start
- `object`: `data` is serialized as JSON.
- `string`: `data` is written as-is.
- If JSON serialization fails (for example, if a cyclical reference is found), a `400` error is thrown. See [Error Handling](#error-handling).
-- Example
-
- ```js
- const { send } = require('micro')
- module.exports = async function (req, res) {
- send(res, 400, { error: 'Please use a valid email' });
- }
- ```
-
-#### return
-**`return val;`**
-
-- Returning `val` from your function is shorthand for: `send(res, 200, val)`.
-- Example
-
- ```js
- module.exports = function (req, res) {
- return {message: 'Hello!'};
- }
- ```
-
-- Returning a promise works as well!
-- Example
-
- ```js
- const sleep = require('then-sleep')
- module.exports = async function (req, res) {
- return new Promise(async (resolve) => {
- await sleep(100);
- resolve('I Promised');
- });
- }
- ```
+### Programmatic use
-#### sendError
+You can use micro programmatically by requiring micro directly:
-**`sendError(req, res, error)`**
+```js
+const micro = require('micro')
+const sleep = require('then-sleep')
-- Use `require('micro').sendError`.
-- Used as the default handler for errors thrown.
-- Automatically sets the status code of the response based on `error.statusCode`.
-- Sends the `error.message` as the body.
-- Stacks are printed out with `console.error` and during development (when `NODE_ENV` is set to `'development'`) also sent in responses.
-- Usually, you don't need to invoke this method yourself, as you can use the [built-in error handling](#error-handling) flow with `throw`.
+const server = micro(async function (req, res) {
+ await sleep(500)
+ return 'Hello world'
+})
-#### createError
+server.listen(3000)
+```
-**`createError(code, msg, orig)`**
+#### API
-- Use `require('micro').createError`.
-- Creates an error object with a `statusCode`.
-- Useful for easily throwing errors with HTTP status codes, which are interpreted by the [built-in error handling](#error-handling).
-- `orig` sets `error.originalError` which identifies the original error (if any).
+**`micro(fn)`**
-
+- This function is exposed as the `default` export.
+- Use `require('micro')`.
+- Returns a [`http.Server`](https://nodejs.org/dist/latest-v6.x/docs/api/http.html#http_class_http_server) that uses the provided `function` as the request handler.
+- The supplied function is run with `await`. So it can be `async`
### Error handling
@@ -191,26 +181,26 @@ If the `Error` object that's thrown contains a `statusCode` property, that's use
```js
const rateLimit = require('my-rate-limit')
module.exports = async function (req, res) {
- await rateLimit(req);
+ await rateLimit(req)
// … your code
}
```
-If the API endpoint is abused, it can throw an error like so:
+If the API endpoint is abused, it can throw an error with ``createError`` like so:
```js
if (tooMany) {
- const err = new Error('Rate limit exceeded');
- err.statusCode = 429;
- throw err;
+ throw createError(429, 'Rate limit exceeded')
}
```
-Alternatively you can use ``createError`` as described above.
+Alternatively you can create the `Error` object yourself
```js
if (tooMany) {
- throw createError(429, 'Rate limit exceeded')
+ const err = new Error('Rate limit exceeded')
+ err.statusCode = 429
+ throw err
}
```
@@ -218,11 +208,11 @@ The nice thing about this model is that the `statusCode` is merely a suggestion.
```js
try {
- await rateLimit(req);
+ await rateLimit(req)
} catch (err) {
if (429 == err.statusCode) {
// perhaps send 500 instead?
- send(res, 500);
+ send(res, 500)
}
}
```
@@ -234,45 +224,64 @@ If a generic error is caught, the status will be set to `500`.
In order to set up your own error handling mechanism, you can use composition in your handler:
```js
+const { send } = require('micro')
module.exports = handleErrors(async (req, res) => {
- throw new Error('What happened here?');
-});
+ throw new Error('What happened here?')
+})
function handleErrors (fn) {
return async function (req, res) {
try {
- return await fn(req, res);
+ return await fn(req, res)
} catch (err) {
- console.log(err.stack);
- send(res, 500, 'My custom error!');
+ console.log(err.stack)
+ send(res, 500, 'My custom error!')
}
}
}
```
+#### API
+
+**`sendError(req, res, error)`**
+
+- Use `require('micro').sendError`.
+- Used as the default handler for errors thrown.
+- Automatically sets the status code of the response based on `error.statusCode`.
+- Sends the `error.message` as the body.
+- Stacks are printed out with `console.error` and during development (when `NODE_ENV` is set to `'development'`) also sent in responses.
+- Usually, you don't need to invoke this method yourself, as you can use the [built-in error handling](#error-handling) flow with `throw`.
+
+**`createError(code, msg, orig)`**
+
+- Use `require('micro').createError`.
+- Creates an error object with a `statusCode`.
+- Useful for easily throwing errors with HTTP status codes, which are interpreted by the [built-in error handling](#error-handling).
+- `orig` sets `error.originalError` which identifies the original error (if any).
+
### Testing
Micro makes tests compact and a pleasure to read and write.
We recommend [ava](https://github.com/sindresorhus/ava), a highly parallel micro test framework with built-in support for async tests:
```js
-const micro = require('micro');
-const test = require('ava');
-const listen = require('test-listen');
-const request = require('request-promise');
+const micro = require('micro')
+const test = require('ava')
+const listen = require('test-listen')
+const request = require('request-promise')
test('my endpoint', async t => {
const service = micro(async function (req, res) {
micro.send(res, 200, { test: 'woot' })
- });
+ })
- const url = await listen(service);
- const body = await request(url);
- t.deepEqual(JSON.parse(body).test, 'woot');
-});
+ const url = await listen(service)
+ const body = await request(url)
+ t.deepEqual(JSON.parse(body).test, 'woot')
+})
```
-Look at the [test-listen](https://github.com/zeit/test-listen) for a
+Look at [test-listen](https://github.com/zeit/test-listen) for a
function that returns a URL with an ephemeral port every time it's called.
### Transpilation
@@ -312,6 +321,22 @@ You can use the `micro` CLI for `npm start`:
Then simply run `npm start`!
+#### Port based on environment variable
+
+When you want to set the port using an environment variable you can use:
+
+```
+micro -p $PORT
+```
+
+Optionally you can add a default if it suits your use case:
+
+```
+micro -p ${PORT:-3000}
+```
+
+`${PORT:-3000}` will allow a fallback to port `3000` when `$PORT` is not defined
+
## Contribute
1. [Fork](https://help.github.com/articles/fork-a-repo/) this repository to your own GitHub account and then [clone](https://help.github.com/articles/cloning-a-repository/) it to your local device
diff --git a/examples/external-api-call/README.md b/examples/external-api-call/README.md
new file mode 100644
index 0000000..ad89423
--- /dev/null
+++ b/examples/external-api-call/README.md
@@ -0,0 +1,28 @@
+
+# External API call example
+
+## How to use
+
+Download the example [or clone the repo](https://github.com/zeit/micro):
+
+```bash
+curl https://codeload.github.com/zeit/micro/tar.gz/master | tar -xz --strip=2 micro-master/examples/external-api-call
+cd external-api-call
+```
+
+Install it and run:
+
+```bash
+npm install
+npm run start
+```
+
+Deploy it to the cloud with [now](https://zeit.co/now) ([download](https://zeit.co/download))
+
+```bash
+now
+```
+
+## The idea behind the example
+
+Shows how to get data from an external api using async/await.
diff --git a/examples/external-api-call/index.js b/examples/external-api-call/index.js
new file mode 100644
index 0000000..d61b3cf
--- /dev/null
+++ b/examples/external-api-call/index.js
@@ -0,0 +1,8 @@
+const fetch = require('node-fetch')
+
+module.exports = async function (req, res) {
+ const response = await fetch('https://api.example.com')
+ const json = await response.json()
+
+ return json.example
+}
diff --git a/examples/external-api-call/package.json b/examples/external-api-call/package.json
new file mode 100644
index 0000000..a7d99c3
--- /dev/null
+++ b/examples/external-api-call/package.json
@@ -0,0 +1,14 @@
+{
+ "name": "external-api-call",
+ "version": "1.0.0",
+ "main": "index.js",
+ "scripts": {
+ "start": "micro"
+ },
+ "dependencies": {
+ "micro": "latest",
+ "node-fetch": "latest"
+ },
+ "author": "",
+ "license": "MIT"
+}
diff --git a/examples/json-body-parsing/README.md b/examples/json-body-parsing/README.md
new file mode 100644
index 0000000..3bed216
--- /dev/null
+++ b/examples/json-body-parsing/README.md
@@ -0,0 +1,28 @@
+
+# Parse JSON body example
+
+## How to use
+
+Download the example [or clone the repo](https://github.com/zeit/micro):
+
+```bash
+curl https://codeload.github.com/zeit/micro/tar.gz/master | tar -xz --strip=2 micro-master/examples/json-body-parsing
+cd json-body-parsing
+```
+
+Install it and run:
+
+```bash
+npm install
+npm run start
+```
+
+Deploy it to the cloud with [now](https://zeit.co/now) ([download](https://zeit.co/download))
+
+```bash
+now
+```
+
+## The idea behind the example
+
+Shows how to get data posted to your microservice using async/await.
diff --git a/examples/json-body-parsing/index.js b/examples/json-body-parsing/index.js
new file mode 100644
index 0000000..169fe1e
--- /dev/null
+++ b/examples/json-body-parsing/index.js
@@ -0,0 +1,8 @@
+const {json} = require('micro')
+
+module.exports = async function (req, res) {
+ const data = await json(req)
+ console.log(data)
+
+ return 'Data logged to your console'
+}
diff --git a/examples/json-body-parsing/package.json b/examples/json-body-parsing/package.json
new file mode 100644
index 0000000..697cfdf
--- /dev/null
+++ b/examples/json-body-parsing/package.json
@@ -0,0 +1,13 @@
+{
+ "name": "json-body-parsing",
+ "version": "1.0.0",
+ "main": "index.js",
+ "scripts": {
+ "start": "micro"
+ },
+ "dependencies": {
+ "micro": "latest"
+ },
+ "author": "",
+ "license": "MIT"
+}
diff --git a/examples/urlencoded-body-parsing/README.md b/examples/urlencoded-body-parsing/README.md
new file mode 100644
index 0000000..3bdbd01
--- /dev/null
+++ b/examples/urlencoded-body-parsing/README.md
@@ -0,0 +1,28 @@
+
+# Parse JSON body example
+
+## How to use
+
+Download the example [or clone the repo](https://github.com/zeit/micro):
+
+```bash
+curl https://codeload.github.com/zeit/micro/tar.gz/master | tar -xz --strip=2 micro-master/examples/urlencoded-body-parsing
+cd urlencoded-body-parsing
+```
+
+Install it and run:
+
+```bash
+npm install
+npm run start
+```
+
+Deploy it to the cloud with [now](https://zeit.co/now) ([download](https://zeit.co/download))
+
+```bash
+now
+```
+
+## The idea behind the example
+
+Shows how to get urlencoded (html form post) data posted to your microservice using async/await.
diff --git a/examples/urlencoded-body-parsing/index.js b/examples/urlencoded-body-parsing/index.js
new file mode 100644
index 0000000..89027fb
--- /dev/null
+++ b/examples/urlencoded-body-parsing/index.js
@@ -0,0 +1,8 @@
+const parse = require('urlencoded-body-parser')
+
+module.exports = async function (req, res) {
+ const data = await parse(req)
+ console.log(data)
+
+ return 'Data logged to your console'
+}
diff --git a/examples/urlencoded-body-parsing/package.json b/examples/urlencoded-body-parsing/package.json
new file mode 100644
index 0000000..62df131
--- /dev/null
+++ b/examples/urlencoded-body-parsing/package.json
@@ -0,0 +1,14 @@
+{
+ "name": "urlencoded-body-parsing",
+ "version": "1.0.0",
+ "main": "index.js",
+ "scripts": {
+ "start": "micro"
+ },
+ "dependencies": {
+ "micro": "latest",
+ "urlencoded-body-parser": "latest"
+ },
+ "author": "",
+ "license": "MIT"
+}
diff --git a/package.json b/package.json
index e58d24d..9be7eb2 100644
--- a/package.json
+++ b/package.json
@@ -21,6 +21,9 @@
"esnext": true,
"space": true,
"semicolon": false,
+ "ignores": [
+ "examples/**/*"
+ ],
"rules": {
"max-lines": 0,
"ava/no-ignored-test-files": 0,