diff --git a/docs/api/request.md b/docs/api/request.md index 803d804..ee6ab9c 100644 --- a/docs/api/request.md +++ b/docs/api/request.md @@ -167,7 +167,7 @@ this.body = yield db.find('something'); If `app.subdomainOffset` is not set, this.subdomains is `["ferrets", "tobi"]`. If `app.subdomainOffset` is 3, this.subdomains is `["tobi"]`. -### req.is(type) +### req.is(types...) Check if the incoming request contains the "Content-Type" header field, and it contains any of the give mime `type`s. @@ -346,4 +346,3 @@ this.acceptsLanguages(); ### req.get(field) Return request header. - diff --git a/docs/api/response.md b/docs/api/response.md index 86e3bda..4e80207 100644 --- a/docs/api/response.md +++ b/docs/api/response.md @@ -20,7 +20,7 @@ ### res.status= - Set response status via numeric code or case-insensitive string: + Set response status via numeric code: - 100 "continue" - 101 "switching protocols" @@ -182,6 +182,33 @@ this.type = 'png'; when explicitly defined in full as `res.type = 'text/html'` no charset is assigned. +### res.is(types...) + + Very similar to `this.request.is()`. + Check whether the response type is one of the supplied types. + This is particularly useful for creating middleware that + change certain responses. + + For example, this is a middleware that minifies + all HTML response except for streamss. + +```js +var minify = require('html-minifier'); + +app.use(function *minifyHTML(next){ + yield* next; + + if (!this.response.is('html')) return; + + var body = this.response.body; + if (!body) return; + // too difficult to do this with a stream + if ('function' == typeof body.pipe) return; + if (Buffer.isBuffer(body)) body = body.toString('utf8'); + this.response.body = minify(body); +}); +``` + ### res.redirect(url, [alt]) Perform a [302] redirect to `url`. diff --git a/lib/response.js b/lib/response.js index 41a9b8c..535c134 100644 --- a/lib/response.js +++ b/lib/response.js @@ -8,6 +8,7 @@ var getType = require('mime-types').contentType; var isJSON = require('koa-is-json'); var escape = require('escape-html'); var onfinish = require('finished'); +var typeis = require('type-is').is; var status = require('statuses'); var destroy = require('dethroy'); var assert = require('assert'); @@ -338,6 +339,22 @@ module.exports = { return type.split(';')[0]; }, + /** + * Check whether the response is one of the listed types. + * Pretty much the same as `this.request.is()`. + * + * @param {String|Array} types... + * @return {String|false} + * @api public + */ + + is: function(types){ + var type = this.type; + if (!types) return type || false; + if (!Array.isArray(types)) types = [].slice.call(arguments); + return typeis(type, types); + }, + /** * Return response header. * diff --git a/test/response/is.js b/test/response/is.js new file mode 100644 index 0000000..68427cf --- /dev/null +++ b/test/response/is.js @@ -0,0 +1,80 @@ + +var context = require('../context'); +var should = require('should'); +var assert = require('assert'); + +describe('response.is(type)', function(){ + it('should ignore params', function(){ + var res = context().response; + res.type = 'text/html; charset=utf-8'; + + res.is('text/*').should.equal('text/html'); + }) + + describe('when no type is set', function(){ + it('should return false', function(){ + var res = context().response; + + assert(false === res.is()); + assert(false === res.is('html')); + }) + }) + + describe('when given no types', function(){ + it('should return the type', function(){ + var res = context().response; + res.type = 'text/html; charset=utf-8'; + + res.is().should.equal('text/html'); + }) + }) + + describe('given one type', function(){ + it('should return the type or false', function(){ + var res = context().response; + res.type = 'image/png'; + + res.is('png').should.equal('png'); + res.is('.png').should.equal('.png'); + res.is('image/png').should.equal('image/png'); + res.is('image/*').should.equal('image/png'); + res.is('*/png').should.equal('image/png'); + + res.is('jpeg').should.be.false; + res.is('.jpeg').should.be.false; + res.is('image/jpeg').should.be.false; + res.is('text/*').should.be.false; + res.is('*/jpeg').should.be.false; + }) + }) + + describe('given multiple types', function(){ + it('should return the first match or false', function(){ + var res = context().response; + res.type = 'image/png'; + + res.is('png').should.equal('png'); + res.is('.png').should.equal('.png'); + res.is('text/*', 'image/*').should.equal('image/png'); + res.is('image/*', 'text/*').should.equal('image/png'); + res.is('image/*', 'image/png').should.equal('image/png'); + res.is('image/png', 'image/*').should.equal('image/png'); + + res.is('jpeg').should.be.false; + res.is('.jpeg').should.be.false; + res.is('text/*', 'application/*').should.be.false; + res.is('text/html', 'text/plain', 'application/json; charset=utf-8').should.be.false; + }) + }) + + describe('when Content-Type: application/x-www-form-urlencoded', function(){ + it('should match "urlencoded"', function(){ + var res = context().response; + res.type = 'application/x-www-form-urlencoded'; + + res.is('urlencoded').should.equal('urlencoded'); + res.is('json', 'urlencoded').should.equal('urlencoded'); + res.is('urlencoded', 'json').should.equal('urlencoded'); + }) + }) +})