Browse Source

[WIP] Rewrite docs to include examples (#115)

* Rewrite docs to inlude examples

* Add proposed changes to README.md

* Add docs for logging

* Revert "Add docs for logging"

This reverts commit dff3225ae7bbfa2f6371370fb7923713cfcf50f9.

* Add instruction for port based on environment variable

* Remove command line indicator

* Added examples

* Add missing code block

* Api -> API

* Add README and package.json to all examples

* Fix linting errors

* Remove semicolons

* Ignore examples dir
master
Tim Neutkens 8 years ago
committed by Leo Lamprecht
parent
commit
c7de7e8d9e
  1. 289
      README.md
  2. 28
      examples/external-api-call/README.md
  3. 8
      examples/external-api-call/index.js
  4. 14
      examples/external-api-call/package.json
  5. 28
      examples/json-body-parsing/README.md
  6. 8
      examples/json-body-parsing/index.js
  7. 13
      examples/json-body-parsing/package.json
  8. 28
      examples/urlencoded-body-parsing/README.md
  9. 8
      examples/urlencoded-body-parsing/index.js
  10. 14
      examples/urlencoded-body-parsing/package.json
  11. 3
      package.json

289
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
<p><details>
<summary><b>Examples</b></summary>
<ul><li><a href="./examples/external-api-call">Fetch external api</a></li></ul>
</details></p>
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)`**
<p id="body-parsing-examples"><details>
<summary><b>Examples</b></summary>
<ul>
<li><a href="./examples/json-body-parsing">Parse JSON</a></li>
<li><a href="./examples/urlencoded-body-parsing">Parse urlencoded form (html `form` tag)</a></li>
</ul>
</details></p>
- 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)`**
<a name="error-handling"></a>
- 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

28
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.

8
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
}

14
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"
}

28
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.

8
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'
}

13
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"
}

28
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.

8
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'
}

14
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"
}

3
package.json

@ -21,6 +21,9 @@
"esnext": true,
"space": true,
"semicolon": false,
"ignores": [
"examples/**/*"
],
"rules": {
"max-lines": 0,
"ava/no-ignored-test-files": 0,

Loading…
Cancel
Save