Skip to content

Commit b2fb75c

Browse files
committed
Minor refactoring and improved docs
1 parent 6131125 commit b2fb75c

File tree

3 files changed

+97
-55
lines changed

3 files changed

+97
-55
lines changed

README.md

Lines changed: 56 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
# zeit-now-node-server
22

3-
An unofficial package allowing you to create Node Server instances of your Zeit `@now/node` lambdas.
3+
An unofficial package allowing you to create Node [`http.Server`](https://nodejs.org/api/http.html#http_class_http_server) instances of your [Zeit](https://zeit.co/) [`@now/node`](https://zeit.co/docs/builders#official-builders/node-js) lambdas.
44

5-
Doing so allows you to write unit/integration tests for your routes.
5+
Enables you to write unit/integration tests for your lambdas, or to perform manual testing against a local server instance.
66

77
[![npm](https://img.shields.io/npm/v/zeit-now-node-server.svg?style=flat-square)](http://npm.im/zeit-now-node-server)
88
[![MIT License](https://img.shields.io/npm/l/zeit-now-node-server.svg?style=flat-square)](http://opensource.org/licenses/MIT)
@@ -15,19 +15,67 @@ Doing so allows you to write unit/integration tests for your routes.
1515
npm install zeit-now-node-server
1616
```
1717

18-
### Example Jest Test
18+
## Supported API
19+
20+
This package has taken the code from the official [`@now/node`](https://zeit.co/docs/builders#official-builders/node-js) builder in order to ensure maximum API compatibility. As far as I am aware we have 100% API coverage.
21+
22+
## Unit testing your lambdas
23+
24+
In the below example we will make use of a local server in order to perform an integration test against our lambda.
25+
26+
We will be making use of the [`test-listen`](https://github.com/zeit/test-listen) package, which accepts a [`http.Server`](https://nodejs.org/api/http.html#http_class_http_server) instance and will return a unique URL based on an available port.
27+
28+
We will also make use of [`axios`](https://github.com/axios/axios) in order to make the request against our lambda.
1929

2030
```javascript
2131
import { createServer } from 'zeit-now-node-server';
2232
import listen from 'test-listen';
2333
import axios from 'axios';
24-
import routeUnderTest from './api/hello-world';
34+
import helloLambda from './api/hello';
35+
36+
let server;
37+
let url;
38+
39+
beforeAll(() => {
40+
server = createServer(routeUnderTest);
41+
url = await listen(server);
42+
});
43+
44+
afterAll(() => {
45+
server.close();
46+
});
2547

26-
it('should allow me to test my node lambdas' async () => {
27-
const server = createServer(routeUnderTest);
28-
const url = await listen(server);
48+
it('should return the expected response' async () => {
2949
const response = await axios.get(url);
3050
expect(response.data).toBe('Hello world');
31-
server.close();
3251
});
3352
```
53+
54+
## Running a local server
55+
56+
Given the following lambda.
57+
58+
```javascript
59+
const helloLambda = (req, res) => {
60+
res.send(`Hello ${req.query.name}`);
61+
};
62+
```
63+
64+
You can create a Node [`http.Server`](https://nodejs.org/api/http.html#http_class_http_server) instance like so.
65+
66+
```javascript
67+
import { createServer } from 'zeit-node-now-server';
68+
import helloLambda from './api/hello';
69+
70+
const server = createServer(helloLambda);
71+
72+
// start listening on port 8000
73+
server.listen(8000);
74+
```
75+
76+
Then you can then make requests against it.
77+
78+
```bash
79+
> curl http://localhost:8000?name=Pearl
80+
Hello Pearl%
81+
```

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "zeit-now-node-server",
3-
"version": "1.0.0",
3+
"version": "1.0.1",
44
"description": "Create a server for your Zeit @now/node lambdas in order to test them",
55
"license": "MIT",
66
"author": "Sean Matheson",

src/index.ts

Lines changed: 40 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -21,61 +21,55 @@ export class ApiError extends Error {
2121
}
2222
}
2323

24-
function getBodyParser(req: IncomingMessage, body: Buffer) {
25-
return function parseBody(): NowRequestBody {
26-
if (!req.headers['content-type']) {
27-
return undefined;
28-
}
24+
function parseBody(req: IncomingMessage, body: Buffer): NowRequestBody {
25+
if (!req.headers['content-type']) {
26+
return undefined;
27+
}
2928

30-
const { type } = parseContentType(req.headers['content-type']);
29+
const { type } = parseContentType(req.headers['content-type']);
3130

32-
if (type === 'application/json') {
33-
try {
34-
return JSON.parse(body.toString());
35-
} catch (error) {
36-
throw new ApiError(400, 'Invalid JSON');
37-
}
31+
if (type === 'application/json') {
32+
try {
33+
return JSON.parse(body.toString());
34+
} catch (error) {
35+
throw new ApiError(400, 'Invalid JSON');
3836
}
37+
}
3938

40-
if (type === 'application/octet-stream') {
41-
return body;
42-
}
39+
if (type === 'application/octet-stream') {
40+
return body;
41+
}
4342

44-
if (type === 'application/x-www-form-urlencoded') {
45-
// note: querystring.parse does not produce an iterable object
46-
// https://nodejs.org/api/querystring.html#querystring_querystring_parse_str_sep_eq_options
47-
return parseQS(body.toString());
48-
}
43+
if (type === 'application/x-www-form-urlencoded') {
44+
// note: querystring.parse does not produce an iterable object
45+
// https://nodejs.org/api/querystring.html#querystring_querystring_parse_str_sep_eq_options
46+
return parseQS(body.toString());
47+
}
4948

50-
if (type === 'text/plain') {
51-
return body.toString();
52-
}
49+
if (type === 'text/plain') {
50+
return body.toString();
51+
}
5352

54-
return undefined;
55-
};
53+
return undefined;
5654
}
5755

58-
function getQueryParser({ url = '/' }: IncomingMessage) {
59-
return function parseQuery(): NowRequestQuery {
60-
// we provide a placeholder base url because we only want searchParams
61-
const params = new URL(url, 'https://n').searchParams;
56+
function parseQuery({ url = '/' }: IncomingMessage): NowRequestQuery {
57+
// we provide a placeholder base url because we only want searchParams
58+
const params = new URL(url, 'https://n').searchParams;
6259

63-
const query: { [key: string]: string | string[] } = {};
64-
params.forEach((value, name) => {
65-
query[name] = value;
66-
});
67-
return query;
68-
};
60+
const query: { [key: string]: string | string[] } = {};
61+
params.forEach((value, name) => {
62+
query[name] = value;
63+
});
64+
return query;
6965
}
7066

71-
function getCookieParser(req: IncomingMessage) {
72-
return function parseCookie(): NowRequestCookies {
73-
const header: undefined | string | string[] = req.headers.cookie;
74-
if (!header) {
75-
return {};
76-
}
77-
return parse(Array.isArray(header) ? header.join(';') : header);
78-
};
67+
function parseCookie(req: IncomingMessage): NowRequestCookies {
68+
const header: undefined | string | string[] = req.headers.cookie;
69+
if (!header) {
70+
return {};
71+
}
72+
return parse(Array.isArray(header) ? header.join(';') : header);
7973
}
8074

8175
export const createServer = (
@@ -87,9 +81,9 @@ export const createServer = (
8781
body:
8882
typeof bufferOrString === 'string'
8983
? bufferOrString
90-
: getBodyParser(req, bufferOrString)(),
91-
cookies: getCookieParser(req)(),
92-
query: getQueryParser(req)(),
84+
: parseBody(req, bufferOrString),
85+
cookies: parseCookie(req),
86+
query: parseQuery(req),
9387
});
9488
let _status: number;
9589
const nowRes = Object.assign(res, {

0 commit comments

Comments
 (0)