Comparing version 6.2.1 to 7.0.0
{ | ||
"name": "micro", | ||
"version": "6.2.1", | ||
"version": "7.0.0", | ||
"description": "Asynchronous HTTP microservices", | ||
"main": "./dist/index.js", | ||
"main": "./lib/load.js", | ||
"files": [ | ||
"dist", | ||
"bin" | ||
"bin", | ||
"lib" | ||
], | ||
"greenkeeper": { | ||
"emails": false | ||
}, | ||
"scripts": { | ||
"prepublish": "npm run build", | ||
"pretest": "npm run build", | ||
"build": "mkdir -p dist && async-to-gen lib/index.js > dist/index.js", | ||
"test": "xo && ava" | ||
"precommit": "npm run lint", | ||
"lint": "xo", | ||
"test": "npm run lint && ava" | ||
}, | ||
@@ -22,5 +18,2 @@ "ava": { | ||
"async-to-gen/register" | ||
], | ||
"files": [ | ||
"test/index.js" | ||
] | ||
@@ -32,2 +25,5 @@ }, | ||
"semicolon": false, | ||
"ignores": [ | ||
"examples/**/*" | ||
], | ||
"rules": { | ||
@@ -40,8 +36,9 @@ "max-lines": 0, | ||
"yoda": 0, | ||
"no-negated-condition": 0 | ||
"no-negated-condition": 0, | ||
"import/no-dynamic-require": 0, | ||
"unicorn/no-process-exit": 0 | ||
} | ||
}, | ||
"bin": { | ||
"micro": "./bin/micro", | ||
"micro-serve": "./bin/micro" | ||
"micro": "./bin/micro.js" | ||
}, | ||
@@ -66,6 +63,7 @@ "repository": "zeit/micro", | ||
"devDependencies": { | ||
"ava": "^0.17.0", | ||
"ava": "^0.18.1", | ||
"husky": "^0.13.1", | ||
"request": "^2.74.0", | ||
"request-promise": "^4.1.1", | ||
"resumer": "0.0.0", | ||
"resumer": "^0.0.0", | ||
"then-sleep": "^1.0.1", | ||
@@ -75,9 +73,15 @@ "xo": "^0.17.0" | ||
"dependencies": { | ||
"async-to-gen": "1.3.0", | ||
"is-async-supported": "1.2.0", | ||
"isstream": "0.1.2", | ||
"media-typer": "0.3.0", | ||
"minimist": "1.2.0", | ||
"raw-body": "2.2.0" | ||
"args": "^2.2.4", | ||
"async-to-gen": "^1.3.2", | ||
"chalk": "^1.1.3", | ||
"copy-paste": "^1.3.0", | ||
"detect-port": "^1.1.0", | ||
"ip": "^1.1.4", | ||
"is-async-supported": "^1.2.0", | ||
"isstream": "^0.1.2", | ||
"media-typer": "^0.3.0", | ||
"node-version": "^1.0.0", | ||
"raw-body": "^2.2.0", | ||
"update-notifier": "^1.0.3" | ||
} | ||
} |
316
README.md
@@ -1,2 +0,2 @@ | ||
![](https://cldup.com/JDmmHX3uhF.svg) | ||
![](https://raw.githubusercontent.com/zeit/art/31913be3107827adf10e1f491ec61480f63e19af/micro/logo.png) | ||
@@ -18,79 +18,91 @@ _**Micro —** Async ES6 HTTP microservices_ | ||
* **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 | ||
## Usage | ||
The following example `sleep.js` will wait before responding (without blocking!) | ||
Firstly, install it: | ||
```js | ||
const {send} = require('micro') | ||
const sleep = require('then-sleep') | ||
```bash | ||
npm install --save micro | ||
``` | ||
module.exports = async function (req, res) { | ||
await sleep(500) | ||
send(res, 200, 'Ready!') | ||
Then add a `start` script to your `package.json` like this: | ||
```json | ||
{ | ||
"main": "index.js", | ||
"scripts": { | ||
"start": "micro" | ||
} | ||
} | ||
``` | ||
To run the microservice on port `3000`, use the `micro` command: | ||
After that, we have to create an `index.js` file and populate it: | ||
```bash | ||
micro sleep.js | ||
```js | ||
module.exports = (req, res) => 'Welcome to micro' | ||
``` | ||
To run the microservice on port `3000` and localhost instead of listening on every interface, use the `micro` command: | ||
Once all of that is done, just start the server: | ||
```bash | ||
micro -H localhost sleep.js | ||
npm start | ||
``` | ||
## Usage | ||
And go to this URL: `http://localhost:3000` - 🎉 | ||
Install the package (requires at least Node v6): | ||
### `async` & `await` | ||
```js | ||
npm install --save micro | ||
``` | ||
<p><details> | ||
<summary><b>Examples</b></summary> | ||
<ul><li><a href="./examples/external-api-call">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" | ||
const sleep = require('then-sleep') | ||
module.exports = async (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. | ||
### API | ||
`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. | ||
#### micro | ||
**`micro(fn)`** | ||
### Body parsing | ||
- 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: | ||
<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> | ||
```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); | ||
``` | ||
For parsing the incoming request body we included an async function `json` | ||
#### json | ||
```js | ||
const {json} = require('micro') | ||
module.exports = async (req, res) => { | ||
const data = await json(req) | ||
console.log(data.price) | ||
return '' | ||
} | ||
``` | ||
#### API | ||
**`json(req, { limit = '1mb' })`** | ||
@@ -104,15 +116,22 @@ | ||
- 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); | ||
} | ||
``` | ||
For other types of data check the [examples](#body-parsing-examples) | ||
#### send | ||
### 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 (req, res) => { | ||
const statusCode = 400 | ||
const data = { error: 'Custom error message' } | ||
send(res, statusCode, data) | ||
} | ||
``` | ||
#### API | ||
**`send(res, statusCode, data = null)`** | ||
@@ -128,59 +147,28 @@ | ||
- 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' }); | ||
} | ||
``` | ||
### Programmatic use | ||
#### return | ||
You can use micro programmatically by requiring micro directly: | ||
**`return val;`** | ||
```js | ||
const micro = require('micro') | ||
const sleep = require('then-sleep') | ||
- Returning `val` from your function is shorthand for: `send(res, 200, val)`. | ||
- Example | ||
const server = micro(async (req, res) => { | ||
await sleep(500) | ||
return 'Hello world' | ||
}) | ||
```js | ||
module.exports = function (req, res) { | ||
return {message: 'Hello!'}; | ||
} | ||
``` | ||
server.listen(3000) | ||
``` | ||
- Returning a promise works as well! | ||
- Example | ||
#### API | ||
```js | ||
const sleep = require('then-sleep') | ||
module.exports = async function (req, res) { | ||
return new Promise(async (resolve) => { | ||
await sleep(100); | ||
resolve('I Promised'); | ||
}); | ||
} | ||
``` | ||
**`micro(fn)`** | ||
#### sendError | ||
- 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` | ||
**`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 | ||
**`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). | ||
<a name="error-handling"></a> | ||
### Error handling | ||
@@ -190,3 +178,3 @@ | ||
If an error is thrown and not caught by you, the response will automatically be `500`. **Important:** during development mode (if the env variable `NODE_ENV` is `'development'`), error stacks will be printed as `console.error` and included in the responses. | ||
If an error is thrown and not caught by you, the response will automatically be `500`. **Important:** Error stacks will be printed as `console.error` and during development mode (if the env variable `NODE_ENV` is `'development'`), they will also be included in the responses. | ||
@@ -197,23 +185,24 @@ If the `Error` object that's thrown contains a `statusCode` property, that's used as the HTTP code to be sent. Let's say you want to write a rate limiting module: | ||
const rateLimit = require('my-rate-limit') | ||
module.exports = async function (req, res) { | ||
await rateLimit(req); | ||
// … your code | ||
module.exports = async (req, res) => { | ||
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 | ||
} | ||
@@ -226,7 +215,7 @@ ``` | ||
try { | ||
await rateLimit(req); | ||
await rateLimit(req) | ||
} catch (err) { | ||
if (429 == err.statusCode) { | ||
// perhaps send 500 instead? | ||
send(res, 500); | ||
send(res, 500) | ||
} | ||
@@ -243,18 +232,36 @@ } | ||
```js | ||
module.exports = handleErrors(async (req, res) => { | ||
throw new Error('What happened here?'); | ||
}); | ||
const {send} = require('micro') | ||
function handleErrors (fn) { | ||
return async function (req, res) { | ||
try { | ||
return await fn(req, res); | ||
} catch (err) { | ||
console.log(err.stack); | ||
send(res, 500, 'My custom error!'); | ||
} | ||
const handleErrors = fn => async (req, res) => { | ||
try { | ||
return await fn(req, res) | ||
} catch (err) { | ||
console.log(err.stack) | ||
send(res, 500, 'My custom error!') | ||
} | ||
} | ||
module.exports = handleErrors(async (req, res) => { | ||
throw new Error('What happened here?') | ||
}) | ||
``` | ||
#### 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 | ||
@@ -266,19 +273,22 @@ | ||
```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 service = micro(async (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. | ||
@@ -298,2 +308,8 @@ | ||
To use native `async/await` on Node v7.x, run `micro` like the following. | ||
```bash | ||
node --harmony-async-await node_modules/.bin/micro . | ||
``` | ||
### Deployment | ||
@@ -311,3 +327,3 @@ | ||
"scripts": { | ||
"start": "micro -p 3000" | ||
"start": "micro" | ||
} | ||
@@ -319,2 +335,18 @@ } | ||
#### 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 | ||
@@ -321,0 +353,0 @@ |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
Dynamic require
Supply chain riskDynamic require can indicate the package is performing dangerous or unsafe dynamic code execution.
Found 1 instance in 1 package
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 2 instances in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
21574
8
269
358
12
7
8
2
+ Addedargs@^2.2.4
+ Addedchalk@^1.1.3
+ Addedcopy-paste@^1.3.0
+ Addeddetect-port@^1.1.0
+ Addedip@^1.1.4
+ Addednode-version@^1.0.0
+ Addedupdate-notifier@^1.0.3
+ Addedaddress@1.2.2(transitive)
+ Addedansi-align@1.1.0(transitive)
+ Addedansi-regex@2.1.1(transitive)
+ Addedansi-styles@2.2.1(transitive)
+ Addedargs@2.6.1(transitive)
+ Addedasync-to-gen@1.4.0(transitive)
+ Addedboxen@0.6.0(transitive)
+ Addedbytes@3.1.2(transitive)
+ Addedcamelcase@2.1.14.1.0(transitive)
+ Addedcapture-stack-trace@1.0.2(transitive)
+ Addedchalk@1.1.3(transitive)
+ Addedcli-boxes@1.0.0(transitive)
+ Addedcode-point-at@1.1.0(transitive)
+ Addedconfigstore@2.1.0(transitive)
+ Addedcopy-paste@1.5.3(transitive)
+ Addedcore-util-is@1.0.3(transitive)
+ Addedcreate-error-class@3.0.2(transitive)
+ Addeddebug@4.4.0(transitive)
+ Addeddeep-extend@0.6.0(transitive)
+ Addeddepd@2.0.0(transitive)
+ Addeddetect-port@1.6.1(transitive)
+ Addeddot-prop@3.0.0(transitive)
+ Addedduplexer2@0.1.4(transitive)
+ Addederror-ex@1.3.2(transitive)
+ Addedescape-string-regexp@1.0.5(transitive)
+ Addedfilled-array@1.1.0(transitive)
+ Addedgot@5.7.1(transitive)
+ Addedgraceful-fs@4.2.11(transitive)
+ Addedhas-ansi@2.0.0(transitive)
+ Addedhttp-errors@2.0.0(transitive)
+ Addediconv-lite@0.4.24(transitive)
+ Addedimurmurhash@0.1.4(transitive)
+ Addedinherits@2.0.4(transitive)
+ Addedini@1.3.8(transitive)
+ Addedip@1.1.9(transitive)
+ Addedis-arrayish@0.2.1(transitive)
+ Addedis-finite@1.1.0(transitive)
+ Addedis-fullwidth-code-point@1.0.0(transitive)
+ Addedis-npm@1.0.0(transitive)
+ Addedis-obj@1.0.1(transitive)
+ Addedis-redirect@1.0.0(transitive)
+ Addedis-retry-allowed@1.2.0(transitive)
+ Addedis-stream@1.1.0(transitive)
+ Addedisarray@1.0.0(transitive)
+ Addedlatest-version@2.0.0(transitive)
+ Addedlazy-req@1.1.0(transitive)
+ Addedlodash@4.17.21(transitive)
+ Addedlowercase-keys@1.0.1(transitive)
+ Addedmagic-string@0.22.5(transitive)
+ Addedminimist@1.2.8(transitive)
+ Addedmkdirp@0.5.6(transitive)
+ Addedms@2.1.3(transitive)
+ Addednode-modules-regexp@1.0.0(transitive)
+ Addednode-status-codes@1.0.0(transitive)
+ Addednode-version@1.2.0(transitive)
+ Addednumber-is-nan@1.0.1(transitive)
+ Addedobject-assign@4.1.1(transitive)
+ Addedos-homedir@1.0.2(transitive)
+ Addedos-tmpdir@1.0.2(transitive)
+ Addedosenv@0.1.5(transitive)
+ Addedpackage-json@2.4.0(transitive)
+ Addedparse-json@2.2.0(transitive)
+ Addedpinkie@2.0.4(transitive)
+ Addedpinkie-promise@2.0.1(transitive)
+ Addedpirates@3.0.2(transitive)
+ Addedpkginfo@0.4.0(transitive)
+ Addedprepend-http@1.0.4(transitive)
+ Addedprocess-nextick-args@2.0.1(transitive)
+ Addedraw-body@2.5.2(transitive)
+ Addedrc@1.2.8(transitive)
+ Addedread-all-stream@3.1.0(transitive)
+ Addedreadable-stream@2.3.8(transitive)
+ Addedregistry-auth-token@3.4.0(transitive)
+ Addedregistry-url@3.1.0(transitive)
+ Addedrepeating@2.0.1(transitive)
+ Addedsafe-buffer@5.1.2(transitive)
+ Addedsafer-buffer@2.1.2(transitive)
+ Addedsemver@5.7.2(transitive)
+ Addedsemver-diff@2.1.0(transitive)
+ Addedsetprototypeof@1.2.0(transitive)
+ Addedslide@1.1.6(transitive)
+ Addedstatuses@2.0.1(transitive)
+ Addedstring-similarity@1.1.0(transitive)
+ Addedstring-width@1.0.2(transitive)
+ Addedstring_decoder@1.1.1(transitive)
+ Addedstrip-ansi@3.0.1(transitive)
+ Addedstrip-json-comments@2.0.1(transitive)
+ Addedsupports-color@2.0.0(transitive)
+ Addedtimed-out@3.1.3(transitive)
+ Addedtoidentifier@1.0.1(transitive)
+ Addedunzip-response@1.0.2(transitive)
+ Addedupdate-notifier@1.0.3(transitive)
+ Addedurl-parse-lax@1.0.0(transitive)
+ Addedutil-deprecate@1.0.2(transitive)
+ Addeduuid@2.0.3(transitive)
+ Addedwidest-line@1.0.0(transitive)
+ Addedwrite-file-atomic@1.3.4(transitive)
+ Addedxdg-basedir@2.0.0(transitive)
- Removedminimist@1.2.0
- Removedasync-to-gen@1.3.0(transitive)
- Removedbytes@2.4.0(transitive)
- Removediconv-lite@0.4.15(transitive)
- Removedmagic-string@0.19.1(transitive)
- Removedraw-body@2.2.0(transitive)
Updatedasync-to-gen@^1.3.2
Updatedis-async-supported@^1.2.0
Updatedisstream@^0.1.2
Updatedmedia-typer@^0.3.0
Updatedraw-body@^2.2.0