Skip to content

Commit

Permalink
feat: accepts* methods added to Request object`
Browse files Browse the repository at this point in the history
  • Loading branch information
muratcorlu committed Sep 2, 2019
1 parent 003d60e commit 49110f2
Show file tree
Hide file tree
Showing 5 changed files with 248 additions and 11 deletions.
7 changes: 6 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -97,8 +97,13 @@ Methods:

| Method | Notes |
|-------------|-------|
| [accepts()](https://expressjs.com/en/4x/api.html#req.accepts) | - |
| [acceptsEncodings()](https://expressjs.com/en/4x/api.html#req.acceptsEncodings) | - |
| [acceptsCharsets()](https://expressjs.com/en/4x/api.html#req.acceptsCharsets) | - |
| [acceptsLanguages()](https://expressjs.com/en/4x/api.html#req.acceptsLanguages) | - |
| [get()](https://expressjs.com/en/4x/api.html#req.get) | - |
| [is()](https://expressjs.com/en/4x/api.html#req.is) | Doesn't support `*` wildcard checks(like `text/*`) |
| [header()](https://expressjs.com/en/4x/api.html#req.header) | - |
| [is()](https://expressjs.com/en/4x/api.html#req.is) | - |

### Response Object

Expand Down
22 changes: 16 additions & 6 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 4 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,5 +23,9 @@
"body-parser": "^1.19.0",
"jest": "^24.9.0",
"semantic-release": "^15.13.21"
},
"dependencies": {
"accepts": "^1.3.7",
"type-is": "^1.6.18"
}
}
171 changes: 168 additions & 3 deletions src/request.js
Original file line number Diff line number Diff line change
@@ -1,15 +1,19 @@
const ReadableStream = require('stream').Readable;
const accepts = require('accepts');
const typeis = require('type-is');

/**
*
*/
class Request extends ReadableStream {
constructor(event) {
super();

this.headers = Object.keys(event.headers).reduce((headers, key) => {
headers[key.toLowerCase()] = event.headers[key];
return headers;
}, {});

this.hostname = this.headers.host
this.method = event.httpMethod;
this.query = event.queryStringParameters;
Expand All @@ -24,17 +28,178 @@ class Request extends ReadableStream {
this.xhr = (this.get('X-Requested-With') || '').toLowerCase() === 'xmlhttprequest';

this.event = event;
this.accept = accepts(this);

this.push(event.body);
this.push(null);
}

/**
* Check if the given `type(s)` is acceptable, returning
* the best match when true, otherwise `undefined`, in which
* case you should respond with 406 "Not Acceptable".
*
* The `type` value may be a single MIME type string
* such as "application/json", an extension name
* such as "json", a comma-delimited list such as "json, html, text/plain",
* an argument list such as `"json", "html", "text/plain"`,
* or an array `["json", "html", "text/plain"]`. When a list
* or array is given, the _best_ match, if any is returned.
*
* Examples:
*
* // Accept: text/html
* req.accepts('html');
* // => "html"
*
* // Accept: text/*, application/json
* req.accepts('html');
* // => "html"
* req.accepts('text/html');
* // => "text/html"
* req.accepts('json, text');
* // => "json"
* req.accepts('application/json');
* // => "application/json"
*
* // Accept: text/*, application/json
* req.accepts('image/png');
* req.accepts('png');
* // => undefined
*
* // Accept: text/*;q=.5, application/json
* req.accepts(['html', 'json']);
* req.accepts('html', 'json');
* req.accepts('html, json');
* // => "json"
*
* @param {String|Array} type(s)
* @return {String|Array|Boolean}
* @public
*/
accepts() {
return this.accept.types.apply(this.accept, arguments);
}

/**
* Check if the given `encoding`s are accepted.
*
* @param {String} ...encoding
* @return {String|Array}
* @public
*/
acceptsEncodings() {
return this.accept.encodings.apply(this.accept, arguments);
}

/**
* Check if the given `charset`s are acceptable,
* otherwise you should respond with 406 "Not Acceptable".
*
* @param {String} ...charset
* @return {String|Array}
* @public
*/
acceptsCharsets() {
return this.accept.charsets.apply(this.accept, arguments);
}

/**
* Check if the given `lang`s are acceptable,
* otherwise you should respond with 406 "Not Acceptable".
*
* @param {String} ...lang
* @return {String|Array}
* @public
*/
acceptsLanguages() {
return this.accept.languages.apply(this.accept, arguments);
}

/**
* Return request header.
*
* The `Referrer` header field is special-cased,
* both `Referrer` and `Referer` are interchangeable.
*
* Examples:
*
* req.get('Content-Type');
* // => "text/plain"
*
* req.get('content-type');
* // => "text/plain"
*
* req.get('Something');
* // => undefined
*
* Aliased as `req.header()`.
*
* @param {String} name
* @return {String}
* @public
*/
get(key) {
return this.headers[key.toLowerCase()];
return this.header(key);
}

header(name) {
if (!name) {
throw new TypeError('name argument is required to req.get');
}

if (typeof name !== 'string') {
throw new TypeError('name must be a string to req.get');
}

const lc = name.toLowerCase();

switch (lc) {
case 'referer':
case 'referrer':
return this.headers.referrer
|| this.headers.referer;
default:
return this.headers[lc];
}
}

is(mimeType) {
return this.get('Content-Type') && this.get('Content-Type').indexOf(mimeType) > -1;
/**
* Check if the incoming request contains the "Content-Type"
* header field, and it contains the give mime `type`.
*
* Examples:
*
* // With Content-Type: text/html; charset=utf-8
* req.is('html');
* req.is('text/html');
* req.is('text/*');
* // => true
*
* // When Content-Type is application/json
* req.is('json');
* req.is('application/json');
* req.is('application/*');
* // => true
*
* req.is('html');
* // => false
*
* @param {String|Array} types...
* @return {String|false|null}
* @public
*/
is(types) {
var arr = types;

// support flattened arguments
if (!Array.isArray(types)) {
arr = new Array(arguments.length);
for (var i = 0; i < arr.length; i++) {
arr[i] = arguments[i];
}
}
return typeis(this, arr);
}
}

Expand Down
55 changes: 54 additions & 1 deletion src/request.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,63 @@ describe('Request object', () => {

expect(request.get('Content-Type')).toBe('application/json');
expect(request.get('content-type')).toBe('application/json');
});

it('should handle weird header asks', () => {
const request = new Request(event);

expect(() => request.get()).toThrow(TypeError('name argument is required to req.get'));
expect(() => request.get({})).toThrow(TypeError('name must be a string to req.get'));
});

it('should read referer/referrer header', () => {
const referer = 'muratcorlu.com';
event.headers['Referer'] = referer;

const request = new Request(event);
expect(request.get('referer')).toBe(referer);
expect(request.get('referrer')).toBe(referer);
})

it('check type', () => {
const request = new Request(event);
expect(request.is('json')).toBe(true);
expect(request.is('json')).toBe('json');
expect(request.is(['html', 'json'])).toBe('json');
expect(request.is('html', 'xml')).toBe(false);
})

it('should check accept header', () => {
event.headers['Accept'] = 'application/json';

const request = new Request(event);
expect(request.accepts('xml')).toBe(false);
expect(request.accepts('text/xml')).toBe(false);
expect(request.accepts('json')).toBe('json');
expect(request.accepts('application/json')).toBe('application/json');
expect(request.accepts(['html', 'json'])).toBe('json');
})

it('should check acceptEncodings', () => {
event.headers['accept-encoding'] = 'gzip, compress;q=0.2';

const request = new Request(event);
expect(request.acceptsEncodings('gzip', 'compress')).toBe('gzip');

});

it('should check acceptsCharsets', () => {
event.headers['accept-charset'] = 'utf-8, iso-8859-1;q=0.2, utf-7;q=0.5';

const request = new Request(event);
expect(request.acceptsCharsets('utf-7', 'utf-8')).toBe('utf-8');

});

it('should check acceptsLanguages', () => {
event.headers['accept-charset'] = 'en;q=0.8, es, tr';

const request = new Request(event);
expect(request.acceptsLanguages('tr', 'en')).toBe('tr');

});
});

0 comments on commit 49110f2

Please sign in to comment.