Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WIP] Rewrite docs to include examples #115

Merged
merged 22 commits into from
Feb 4, 2017
Merged
Changes from 1 commit
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
4fd9d89
Rewrite docs to inlude examples
timweprovide Dec 27, 2016
7a2ee42
Add proposed changes to README.md
timweprovide Jan 2, 2017
71a5479
Merge branch 'master' into rewrite-readme
timneutkens Jan 4, 2017
78c68f5
Merge branch 'master' of github.com:zeit/micro into rewrite-readme
timweprovide Jan 6, 2017
dff3225
Add docs for logging
timweprovide Jan 7, 2017
66459b8
Revert "Add docs for logging"
timweprovide Jan 8, 2017
e888b47
Add instruction for port based on environment variable
timweprovide Jan 8, 2017
9109dfa
Merge branch 'master' into rewrite-readme
timneutkens Jan 8, 2017
d606d3b
Remove command line indicator
timweprovide Jan 8, 2017
7bf789b
Merge branch 'rewrite-readme' of github.com:timneutkens/micro into re…
timweprovide Jan 8, 2017
4bd11a8
Added examples
timweprovide Jan 8, 2017
c0816fc
Merge branch 'master' into rewrite-readme
timneutkens Jan 9, 2017
7177fa6
Add missing code block
timweprovide Jan 25, 2017
44efb84
Merge branch 'rewrite-readme' of github.com:timneutkens/micro into re…
timweprovide Jan 25, 2017
0b707bb
Api -> API
timweprovide Jan 25, 2017
60f743a
Merge branch 'master' into rewrite-readme
timneutkens Jan 25, 2017
b255a5d
Add README and package.json to all examples
timweprovide Jan 25, 2017
7548b6c
Fix linting errors
timweprovide Jan 25, 2017
bf39868
Merge branch 'master' of github.com:zeit/micro into rewrite-readme
timweprovide Feb 4, 2017
e8cc934
Remove semicolons
timweprovide Feb 4, 2017
9caf4c6
Ignore examples dir
timweprovide Feb 4, 2017
8964b4f
Merge branch 'master' into rewrite-readme
leo Feb 4, 2017
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
256 changes: 124 additions & 132 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,83 +15,94 @@ _**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
## How to use
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Usage

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done 🔥


The following example `sleep.js` will wait before responding (without blocking!)
Install it:

```js
const {send} = require('micro')
const sleep = require('then-sleep')

module.exports = async function (req, res) {
await sleep(500)
send(res, 200, 'Ready!')
}
```
npm install micro --save
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Command line indicator (dollar sign) missing. Also please put the flag before the package name!

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done 🔥

```

To run the microservice on port `3000`, use the `micro` command:
Add a script to your package.json like this:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

package.json, not package.json

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done 🔥


```bash
$ micro -p 3000 sleep.js
```
{
Copy link
Contributor

@onbjerg onbjerg Jan 20, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing opening code fence (```)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed 🙌

"main": "index.js",
"scripts": {
"start": "micro -p 3000"
}
}
```

After that, we have to create an `index.js` file

To run the microservice on port `3000` and localhost instead of listening on every interface, use the `micro` command:
Populate `./index.js` inside your project:

```bash
$ micro -p 3000 -H localhost sleep.js
```js
module.exports = function (req, res) {
return 'Welcome to micro'
}
```

## Usage
and then just run `npm run start` and go to http://localhost:3000

**Note**: `micro` requires Node `6.0.0` or later
So far, we have written a web server that sends 'Welcome to micro'

Install the package:
### Async / Await

```js
$ npm install --save micro
```
<p><details>
<summary><b>Examples</b></summary>
<ul><li><a href="./examples/external-api">Fetch external api</a></li></ul>
</details></p>

And start using it in your `package.json` file:
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 -p 3000"
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). To run your
app and make it listen on `http://localhost:3000` run:
#### Transpilation

```bash
$ npm start
```
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.

### API
If you want to do it manually, you can! `micro(1)` is idempotent and
should not interfere.

#### micro
**`micro(fn)`**
`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.

- 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
### Body parsing

<p id="body-parsing-examples"><details>
<summary><b>Examples</b></summary>
<ul>
<li><a href="./examples/json-parsing">Parse JSON</a></li>
<li><a href="./examples/urlencoded-parsing">Parse urlencoded form (html `<form>`)</a></li>
</ul>
</details></p>

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
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

API (it's an abbreviation)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed 🙌


**`json(req, { limit = '1mb' })`**

Expand All @@ -100,18 +111,23 @@ $ npm start
- Exposes an `async` function that can be run with `await`.
- `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
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

API (it's an abbreviation)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed 🙌


**`send(res, statusCode, data = null)`**

Expand All @@ -123,62 +139,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;`**
### Programmatic use

- 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');
});
}
```
You can use micro programmatically by requiring micro directly:

#### sendError

**`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.
- During development (when `NODE_ENV` is set to `'development'`), stacks are printed out with `console.error` and 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
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

API (it's an abbreviation)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed 🙌


- 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

Expand All @@ -196,21 +181,21 @@ module.exports = async function (req, res) {
}
```

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;
}
```

Expand All @@ -234,6 +219,7 @@ 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?');
});
Expand All @@ -250,6 +236,24 @@ function handleErrors (fn) {
}
```

#### Api
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

API (it's an abbreviation)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed 🙌


**`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.
- During development (when `NODE_ENV` is set to `'development'`), stacks are printed out with `console.error` and 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.
Expand All @@ -271,21 +275,9 @@ test('my endpoint', async t => {
});
```

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

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.

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.

### Deployment

You can use the `micro` CLI for `npm start`:
Expand Down Expand Up @@ -314,4 +306,4 @@ Then simply run `npm start`!

## Credits

Thanks Tom Yandell and Richard Hodgson for donating the `micro` npm name.
Thanks Tom Yandell and Richard Hodgson for donating the `micro` npm name.