UNPKG

8 kBMarkdownView Raw
1**Micro2** — Node.js based asynchronous micro-library (WIP)
2
3[![NPM Version](https://img.shields.io/npm/v/micro2.svg)](https://www.npmjs.com/package/micro2)
4[![node](https://img.shields.io/node/v/micro2.svg)](https://nodejs.org)
5[![Build Status](https://travis-ci.org/rjoydip/micro2.svg?branch=master)](https://travis-ci.org/rjoydip/micro2)
6[![Build status](https://ci.appveyor.com/api/projects/status/qe5x7i3ift8q7rkv/branch/master?svg=true)](https://ci.appveyor.com/project/rjoydip/micro2/branch/master)
7[![dependencies Status](https://david-dm.org/rjoydip/micro2/status.svg)](https://david-dm.org/rjoydip/micro2?type=dev)
8[![devDependencies Status](https://david-dm.org/rjoydip/micro2/dev-status.svg)](https://david-dm.org/rjoydip/micro2?type=dev)
9[![license](https://img.shields.io/badge/license-MIT-blue.svg)](https://img.shields.io/badge/license-MIT-blue.svg)
10[![install size](https://packagephobia.now.sh/badge?p=micro2)](https://packagephobia.now.sh/result?p=micro2)
11[![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg)](https://reactjs.org/docs/how-to-contribute.html#your-first-pull-request)
12
13## Features
14
15* **Easy**: Designed for usage with `async` and `await`
16* **Middleware**: Support middleware
17* **Logging**: It has very low overhead logging method built. [pino](https://www.npmjs.com/package/pino)
18
19## Installation
20
21**Important:** Right now `Micro2` not ready for production application. For making `micro2` a goal is to faster moduler application development. Make your application with moduler way.
22
23```bash
24npm install --save micro2
25```
26
27## Usage
28
29Create an `index.js` file and export a function that accepts the standard [http.IncomingMessage](https://nodejs.org/api/http.html#http_class_http_incomingmessage) and [http.ServerResponse](https://nodejs.org/api/http.html#http_class_http_serverresponse) objects:
30
31```js
32module.exports = (req, res) => {
33 res.end('Welcome to Micro2')
34}
35```
36
37or
38
39```js
40module.exports = () => 'Welcome to Micro2'
41```
42
43### `async` & `await`
44
45<p><details>
46 <summary><b>Examples</b></summary>
47 <ul><li><a href="./examples/external-api-call">Fetch external api</a></li></ul>
48</details></p>
49
50Micro2 is built for usage with async/await. You can read more about async / await.
51
52```js
53const sleep = require('then-sleep')
54
55module.exports = async (req, res) => {
56 await sleep(500)
57 return 'Ready!'
58}
59```
60### API
61
62##### `send(res, statusCode, data = null)`
63
64- Use `require('micro2').send`.
65- `statusCode` is a `Number` with the HTTP status code, and must always be supplied.
66- If `data` is supplied it is sent in the response. Different input types are processed appropriately, and `Content-Type` and `Content-Length` are automatically set.
67 - `string`: `data` is written as-is.
68- If JSON serialization fails (for example, if a cyclical reference is found), a `400` error is thrown.
69
70
71### Sending a different status code
72
73So far we have used `return` to send data to the client. `return 'Hello World'` is the equivalent of `send(res, 200, 'Hello World')`.
74
75```js
76const {send} = require('micro2')
77
78module.exports = async (req, res) => {
79 const statusCode = 400
80 const data = { error: 'Custom error message' }
81
82 send(res, statusCode, data)
83}
84```
85
86
87##### `send(res, statusCode, data = null)`
88
89- Use `require('micro').send`.
90- `statusCode` is a `Number` with the HTTP status code, and must always be supplied.
91- If `data` is supplied it is sent in the response. Different input types are processed appropriately, and `Content-Type` and `Content-Length` are automatically set.
92 - `Stream`: `data` is piped as an `octet-stream`. Note: it is _your_ responsibility to handle the `error` event in this case (usually, simply logging the error and aborting the response is enough).
93 - `Buffer`: `data` is written as an `octet-stream`.
94 - `object`: `data` is serialized as JSON.
95 - `string`: `data` is written as-is.
96- If JSON serialization fails (for example, if a cyclical reference is found), a `400` error is thrown. See [Error Handling](#error-handling).
97
98### Programmatic use
99
100You can use Micro2 programmatically by requiring Micro2 directly:
101
102```js
103const micro2 = require('micro2')
104const sleep = require('then-sleep')
105
106const server = micro2(async (req, res) => {
107 await sleep(500)
108 return 'Hello world'
109})
110
111server.listen(3000)
112```
113
114### Middleware support
115
116You can applied middleware with server.
117
118```js
119server.use((req, res, next) => { // err, req, res
120 log.info('middleware 1')
121 next()
122})
123```
124
125### Logger
126
127Micro2 uses [pino](https://www.npmjs.com/package/pino) for logging. You could enable logging conditionaly. `process.env.NODE_ENV`
128
129```js
130const log = server.log({
131 enabled: true
132})
133```
134
135##### micro2(fn)
136
137- This function is exposed as the `default` export.
138- Use `require('micro2')`.
139- Returns a [`http.createServer`](https://nodejs.org/dist/latest-v6.x/docs/api/http.html#http_class_http_server) that uses the provided `function` as the request handler.
140- The supplied function is run with `await`. So it can be `async`.
141
142##### sendError(req, res, error)
143
144- Use `require('micro').sendError`.
145- Used as the default handler for errors thrown.
146- Automatically sets the status code of the response based on `error.statusCode`.
147- Sends the `error.message` as the body.
148- Stacks are printed out with `console.error` and during development (when `NODE_ENV` is set to `'development'`) also sent in responses.
149- Usually, you don't need to invoke this method yourself, as you can use the [built-in error handling](#error-handling) flow with `throw`.
150
151##### createError(code, msg, orig)
152
153- Use `require('micro').createError`.
154- Creates an error object with a `statusCode`.
155- Useful for easily throwing errors with HTTP status codes, which are interpreted by the [built-in error handling](#error-handling).
156- `orig` sets `error.originalError` which identifies the original error (if any).
157
158## Error Handling
159
160Micro2 allows you to write robust microservices. This is accomplished primarily by bringing sanity back to error handling and avoiding callback soup.
161
162If an error is thrown and not caught by you, the response will automatically be `500`. **Important:** Error stacks will be printed as `error` and during development mode (if the env variable `NODE_ENV` is `'development'`), they will also be included in the responses.
163
164If 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:
165
166```js
167const rateLimit = require('my-rate-limit')
168
169module.exports = async (req, res) => {
170 await rateLimit(req)
171 // ... your code
172}
173```
174
175Alternatively you can create the `Error` object yourself
176
177```js
178if (tooMany) {
179 const err = new Error('Rate limit exceeded')
180 err.statusCode = 429
181 throw err
182}
183```
184
185The nice thing about this model is that the `statusCode` is merely a suggestion. The user can override it:
186
187```js
188try {
189 await rateLimit(req)
190} catch (err) {
191 if (429 == err.statusCode) {
192 // perhaps send 500 instead?
193 send(res, 500)
194 }
195}
196```
197
198If the error is based on another error that **Micro2** caught, like a `JSON.parse` exception, then `originalError` will point to it. If a generic error is caught, the status will be set to `500`.
199
200In order to set up your own error handling mechanism, you can use composition in your handler:
201
202```js
203const {send} = require('micro2')
204
205const handleErrors = fn => async (req, res) => {
206 try {
207 return await fn(req, res)
208 } catch (err) {
209 console.log(err.stack)
210 send(res, 500, 'My custom error!')
211 }
212}
213
214module.exports = handleErrors(async (req, res) => {
215 throw new Error('What happened here?')
216})
217```
218
219## Testing
220
221TODO
222
223## Contributing
224
2251. [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
226
227As always, you can run the [Jest](https://jestjs.io) tests using: `npm test` and [ESLint](http://eslint.org) lint using: `npm run lint`