Skip to content

Commit d71ec2e

Browse files
committed
feat: Headers are case-insensitive now
1 parent 6de3694 commit d71ec2e

File tree

7 files changed

+132
-38
lines changed

7 files changed

+132
-38
lines changed

README.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ Methods:
8181

8282
| Method | Notes |
8383
|-------------|-------|
84-
| [get()](https://expressjs.com/en/4x/api.html#req.get) | Works case sensitive |
84+
| [get()](https://expressjs.com/en/4x/api.html#req.get) | - |
8585
| [is()](https://expressjs.com/en/4x/api.html#req.is) | Doesn't support `*` wildcard checks(like `text/*`) |
8686

8787
### Response Object
@@ -90,8 +90,10 @@ Methods:
9090

9191
| Method | Notes |
9292
|-------------|-------|
93+
| [get()](https://expressjs.com/en/4x/api.html#res.get) | - |
9394
| [set()](https://expressjs.com/en/4x/api.html#res.set) | Only supports `key, value` parameters |
9495
| [send()](https://expressjs.com/en/4x/api.html#res.send) | Only supports string values |
9596
| [status()](https://expressjs.com/en/4x/api.html#res.status) | - |
9697
| [end()](https://expressjs.com/en/4x/api.html#res.end) | - |
9798
| [json()](https://expressjs.com/en/4x/api.html#res.json) | - |
99+
| [type()](https://expressjs.com/en/4x/api.html#res.type) | - |

src/lambda-wrapper.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,12 @@ const { Request } = require('./request');
44
exports.use = (...handlers) => {
55
return (event, context, callback) => {
66
const request = new Request(event);
7-
const response = new Response(callback);
7+
const response = new Response(request, callback);
88

99
handlers = [].concat(...handlers);
1010

1111
handlers.reduce((chain, handler) => chain.then(
12-
() => new Promise((resolve, reject) => handler(request, response, resolve))
12+
() => new Promise((resolve) => handler(request, response, resolve))
1313
).catch(callback), Promise.resolve());
1414
}
1515
}

src/lambda-wrapper.spec.js

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ describe('Lambda Wrapper', () => {
4141
expect(payload).toEqual({
4242
statusCode: 200,
4343
headers: {
44-
'Content-Type': 'application/json'
44+
'content-type': 'application/json'
4545
},
4646
body: '{"a":1}'
4747
});
@@ -81,7 +81,7 @@ describe('Lambda Wrapper', () => {
8181
expect(payload).toEqual({
8282
statusCode: 200,
8383
headers: {
84-
'Content-Type': 'application/json'
84+
'content-type': 'application/json'
8585
},
8686
body: requestObject
8787
});
@@ -104,7 +104,7 @@ describe('Lambda Wrapper', () => {
104104
expect(payload).toEqual({
105105
statusCode: 200,
106106
headers: {
107-
'Content-Type': 'application/json'
107+
'content-type': 'application/json'
108108
},
109109
body: JSON.stringify({"b":"1"})
110110
});
@@ -132,9 +132,12 @@ describe('Lambda Wrapper', () => {
132132
expect(payload).toEqual({
133133
statusCode: 200,
134134
headers: {
135-
'Content-Type': 'application/json'
135+
'content-type': 'application/json'
136136
},
137-
body: JSON.stringify({"b":"1"})
137+
body: JSON.stringify({
138+
fromFirstEndpoint: '1',
139+
fromSecondEndpoint: '1',
140+
})
138141
});
139142
}
140143

@@ -143,11 +146,11 @@ describe('Lambda Wrapper', () => {
143146

144147
it('should handle errors', () => {
145148
const lambdaHandler = use((req, res, next) => {
146-
throw new Error('test');
149+
throw Error('test');
147150
});
148151

149152
const callback = (err, payload) => {
150-
expect(err).toThrow(Error);
153+
expect(err).toStrictEqual(Error('test'));
151154
}
152155

153156
lambdaHandler(proxyRequest, {}, callback);

src/request.js

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,16 @@
1+
/**
2+
*
3+
*/
14
class Request {
25
constructor(event) {
3-
let body = event.body;
4-
if (event.headers['Content-Type'] && event.headers['Content-Type'].indexOf('json') > -1) {
5-
body = JSON.parse(event.body);
6-
}
7-
86
this.method = event.httpMethod;
97
this.query = event.queryStringParameters;
108
this.path = event.path;
119
this.params = event.pathParameters;
12-
this.headers = event.headers;
10+
this.headers = Object.keys(event.headers).reduce((headers, key) => {
11+
headers[key.toLowerCase()] = event.headers[key];
12+
return headers;
13+
}, {});
1314

1415
this.body = event.body;
1516
if (this.is('json')) {
@@ -18,7 +19,7 @@ class Request {
1819
}
1920

2021
get(key) {
21-
return this.headers[key];
22+
return this.headers[key.toLowerCase()];
2223
}
2324

2425
is(mimeType) {

src/request.spec.js

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,13 @@ describe('Request object', () => {
2525
expect(request.body).toEqual(requestObject);
2626
});
2727

28+
it('should read header', () => {
29+
const request = new Request(event);
30+
31+
expect(request.get('Content-Type')).toBe('application/json');
32+
expect(request.get('content-type')).toBe('application/json');
33+
})
34+
2835
it('check type', () => {
2936
const request = new Request(event);
3037
expect(request.is('json')).toBe(true);

src/response.js

Lines changed: 71 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,15 @@
1+
/**
2+
* Response Object
3+
*/
14
class Response {
2-
constructor(callback) {
5+
/**
6+
* Response object constructor
7+
*
8+
* @param {Request} req Request object for this Response
9+
* @param {function} callback AWS Lambda callback function
10+
*/
11+
constructor(req, callback) {
12+
this.req = req;
313
this.callback = callback;
414
this.responseObj = {
515
statusCode: 200,
@@ -8,26 +18,76 @@ class Response {
818
};
919
}
1020

11-
set(key, value) {
12-
this.responseObj.headers[key] = value;
13-
}
14-
status(status) {
15-
this.responseObj.statusCode = status;
21+
/**
22+
* Ends the response process.
23+
*/
24+
end() {
25+
this.callback(null, this.responseObj);
1626
}
1727

18-
send(body) {
19-
this.responseObj.body = body;
20-
this.end();
28+
/**
29+
* Get response header value for given key
30+
*
31+
* @param {string} key Header key to get
32+
*/
33+
get(key) {
34+
return this.responseObj.headers[key.toLowerCase()];
2135
}
2236

37+
/**
38+
* Sends a JSON response. This method sends a response (with the correct content-type) that is the parameter converted to a JSON string using JSON.stringify().
39+
*
40+
* The parameter can be any JSON type, including object, array, string, Boolean, number, or null, and you can also use it to convert other values to JSON.
41+
*
42+
* ```js
43+
* res.json(null)
44+
* res.json({ user: 'tobi' })
45+
* res.status(500).json({ error: 'message' })
46+
* ```
47+
* @param {any} body Any type of oject
48+
*/
2349
json(body) {
2450
this.responseObj.body = JSON.stringify(body);
2551
this.set('Content-Type', 'application/json');
2652
this.end();
2753
}
2854

29-
end() {
30-
this.callback(null, this.responseObj);
55+
/**
56+
* Sends the HTTP response.
57+
*
58+
* @param {any} body
59+
*/
60+
send(body) {
61+
this.responseObj.body = body;
62+
this.end();
63+
}
64+
65+
/**
66+
* Set response header
67+
*
68+
* @param {string} key Header key
69+
* @param {string} value Header value
70+
*/
71+
set(key, value) {
72+
this.responseObj.headers[key.toLowerCase()] = value;
73+
}
74+
75+
/**
76+
* Set status code for response
77+
*
78+
* @param {integer} status Status code. Ex: 200, 201, 400, 404, 500 etc.
79+
*/
80+
status(status) {
81+
this.responseObj.statusCode = status;
82+
}
83+
84+
/**
85+
* Sets the Content-Type HTTP header
86+
*
87+
* @param {string} type Mime type will be set as Content-Type response header
88+
*/
89+
type(type) {
90+
this.set('Content-Type', type);
3191
}
3292
}
3393

src/response.spec.js

Lines changed: 31 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
const { Response } = require('./response');
22

33
describe('Response object', () => {
4-
test('set response status properly', () => {
4+
it('set response status properly', () => {
55
const cb = jest.fn();
66

7-
const response = new Response(cb);
7+
const response = new Response(null, cb);
88

99
response.status(404);
1010
response.end();
@@ -16,18 +16,39 @@ describe('Response object', () => {
1616
});
1717
});
1818

19-
test('send body properly', () => {
20-
const cb = jest.fn();
19+
it('send body properly', () => {
20+
const cb = (err, response) => {
21+
expect(response.body).toBe('hello');
22+
};
2123

22-
const response = new Response(cb);
24+
const response = new Response(null, cb);
2325

2426
response.send('hello');
27+
});
2528

26-
expect(cb).toHaveBeenCalledWith(null, {
27-
statusCode: 200,
28-
headers: {},
29-
body: 'hello'
30-
});
29+
it('set content-type', () => {
30+
const cb = (err, response) => {
31+
expect(response.headers).toBe({
32+
'content-type': 'text/html'
33+
});
34+
};
35+
const response = new Response(null, cb);
36+
37+
response.type('text/html');
38+
39+
});
40+
41+
42+
it('get header', () => {
43+
const cb = (err, response) => {};
44+
45+
const response = new Response(null, cb);
46+
47+
response.set('X-Header', 'a');
48+
49+
expect(response.get('X-Header')).toBe('a');
50+
// Should work case insensitive
51+
expect(response.get('x-Header')).toBe('a');
3152
});
3253
});
3354

0 commit comments

Comments
 (0)