koa-methodoverride
Advanced tools
Comparing version 0.3.1 to 0.4.0
136
index.js
@@ -0,1 +1,10 @@ | ||
/*! | ||
* method-override | ||
* Copyright(c) 2010 Sencha Inc. | ||
* Copyright(c) 2011 TJ Holowaychuk | ||
* Copyright(c) 2014 Jonathan Ong | ||
* Copyright(c) 2014 Douglas Christopher Wilson | ||
* Copyright(c) 2015 Fangdun Cai | ||
* MIT Licensed | ||
*/ | ||
@@ -5,55 +14,120 @@ 'use strict'; | ||
/** | ||
* Module dependences. | ||
* Module dependences. | ||
*/ | ||
var debug = require('debug')('method-override') | ||
var methods = require('methods'); | ||
var METHOD_OVERRIDE_PARAM_KEY = '_method'; | ||
var HTTP_METHOD_OVERRIDE_HEADER = "X-HTTP-Method-Override"; | ||
var ALLOWED_METHODS = ['POST']; | ||
/** | ||
* Method Override: | ||
* Method Override: | ||
* | ||
* Provides faux HTTP method support. | ||
* Provides faux HTTP method support. | ||
* | ||
* Pass an optional `key` to use when checking for | ||
* a method override, otherwise defaults to _\_method_. | ||
* The original method is available via `req.originalMethod`. | ||
* Pass an optional `getter` to use when checking for | ||
* a method override. | ||
* | ||
* @param {String} key | ||
* @return {Function} | ||
* @api public | ||
* A string is converted to a getter that will look for | ||
* the method in `req.body[getter]` and a function will be | ||
* called with `req` and expects the method to be returned. | ||
* If the string starts with `X-` then it will look in | ||
* `req.headers[getter]` instead. | ||
* | ||
* The original method is available via `req.originalMethod`. | ||
* | ||
* @param {string|function} [getter=X-HTTP-Method-Override] | ||
* @param {object} [options] | ||
* @return {function} | ||
* @api public | ||
*/ | ||
module.exports = function methodOverride(key) { | ||
key = key || '_method'; | ||
module.exports = function methodOverride(getter, options){ | ||
options = options || {} | ||
// get the getter fn | ||
var get = typeof getter === 'function' | ||
? getter | ||
: createGetter(getter || HTTP_METHOD_OVERRIDE_HEADER) | ||
// get allowed request methods to examine | ||
var methods = options.methods === undefined | ||
? ALLOWED_METHODS | ||
: options.methods | ||
return function *methodOverride(next) { | ||
var method; | ||
var request = this.request; | ||
request.originalMethod = request.originalMethod || request.method; | ||
var method | ||
var val | ||
var req = this.request | ||
// this.request.body | ||
var body = request.body; | ||
if (body && typeof body === 'object' && key in body) { | ||
method = body[key].toLowerCase(); | ||
delete body[key]; | ||
} | ||
req.originalMethod = req.originalMethod || req.method | ||
// check X-HTTP-Method-Override | ||
var header = request.header; | ||
if (header['x-http-method-override']) { | ||
method = header['x-http-method-override'].toLowerCase(); | ||
// validate request is an allowed method | ||
if (methods && methods.indexOf(req.originalMethod) === -1) { | ||
return yield* next | ||
} | ||
val = get(req, this.response) | ||
method = Array.isArray(val) | ||
? val[0] | ||
: val | ||
// replace | ||
if (supports(method)) request.method = method.toUpperCase(); | ||
if (method !== undefined && supports(method)) { | ||
req.method = method.toUpperCase() | ||
debug('override %s as %s', req.originalMethod, req.method) | ||
} | ||
yield *next; | ||
}; | ||
}; | ||
yield* next | ||
} | ||
} | ||
/** | ||
* Check if node supports `method`. | ||
* Create a getter for the given string. | ||
*/ | ||
function createGetter(str) { | ||
if (str.substr(0, 2).toUpperCase() === 'X-') { | ||
// header getter | ||
return createHeaderGetter(str) | ||
} | ||
return createQueryGetter(str) | ||
} | ||
/** | ||
* Create a getter for the given query key name. | ||
*/ | ||
function createQueryGetter(key) { | ||
return function(req) { | ||
return req.query[key] | ||
} | ||
} | ||
/** | ||
* Create a getter for the given header name. | ||
*/ | ||
function createHeaderGetter(str) { | ||
var header = str.toLowerCase() | ||
return function(req, res) { | ||
// set appropriate Vary header | ||
res.vary(str); | ||
// multiple headers get joined with comma by node.js core | ||
return (req.headers[header] || '').split(/ *, */) | ||
} | ||
} | ||
/** | ||
* Check if node supports `method`. | ||
*/ | ||
function supports(method) { | ||
return ~methods.indexOf(method); | ||
return method | ||
&& typeof method === 'string' | ||
&& methods.indexOf(method.toLowerCase()) !== -1 | ||
} |
{ | ||
"name": "koa-methodoverride", | ||
"version": "0.3.1", | ||
"version": "0.4.0", | ||
"description": "HTTP method override for koa", | ||
@@ -11,3 +11,5 @@ "main": "index.js", | ||
"method", | ||
"override" | ||
"override", | ||
"koa", | ||
"middleware" | ||
], | ||
@@ -17,18 +19,13 @@ "author": "fundon <cfddream@gmail.com>", | ||
"dependencies": { | ||
"methods": "^0.1.0" | ||
"debug": "*", | ||
"methods": "*" | ||
}, | ||
"devDependencies": { | ||
"should": "^3.2.0-beta1", | ||
"supertest": "^0.10.0", | ||
"koa": "^0.5.2", | ||
"mocha": "^1.18.2", | ||
"co-body": "0.0.1" | ||
"co-body": "*", | ||
"koa": "*", | ||
"mocha": "*", | ||
"should": "*", | ||
"supertest": "*" | ||
}, | ||
"repository": { | ||
"type": "git", | ||
"url": "http://github.com/fundon/koa-method-override.git" | ||
}, | ||
"bugs": { | ||
"url": "https://github.com/fundon/koa-method-override/issues" | ||
} | ||
"repository": "koa-modules/koa-method-override" | ||
} |
@@ -1,4 +0,14 @@ | ||
# Method Override [![Build Status](https://travis-ci.org/fundon/koa-method-override.svg)](https://travis-ci.org/fundon/koa-method-override) | ||
> HTTP method override for koa. | ||
# koa-methodoverride | ||
> HTTP method override middleware for koa. | ||
Forked from [Express method-override][] | ||
[![NPM version][npm-img]][npm-url] | ||
[![Build status][travis-img]][travis-url] | ||
[![Test coverage][coveralls-img]][coveralls-url] | ||
[![License][license-img]][license-url] | ||
[![Dependency status][david-img]][david-url] | ||
### Install | ||
@@ -10,33 +20,31 @@ | ||
### Usage | ||
### Usage, more [Express method-override][] | ||
```js | ||
var app = require('koa')(); | ||
var parse = require('co-body'); | ||
var methodOverride = require('koa-methodoverride'); | ||
// First, must parse the body, use the `co-body` or the `koa-bodyparser` etc. | ||
app.use(function *(next) { | ||
try { | ||
this.request.body = yield parse(this); | ||
} catch (e) { | ||
this.request.body = null; | ||
} | ||
yield next; | ||
}); | ||
app.use(methodOverride()); | ||
var key = '_method'; // default | ||
app.use(methodOverride(key)); | ||
app.listen(3000); | ||
``` | ||
### Dependencies | ||
* [co-body](https://github.com/visionmedia/co-body) | ||
* Or other body parser | ||
### License | ||
MIT | ||
### License | ||
MIT | ||
[Express method-override]: https://github.com/expressjs/method-override | ||
[npm-img]: https://img.shields.io/npm/v/koa-methodoverride.svg?style=flat-square | ||
[npm-url]: https://npmjs.org/package/koa-methodoverride | ||
[travis-img]: https://img.shields.io/travis/koa-modules/koa-methodoverride.svg?style=flat-square | ||
[travis-url]: https://travis-ci.org/koa-modules/koa-methodoverride | ||
[coveralls-img]: https://img.shields.io/coveralls/koa-modules/koa-methodoverride.svg?style=flat-square | ||
[coveralls-url]: https://coveralls.io/r/koa-modules/koa-methodoverride?branch=master | ||
[license-img]: https://img.shields.io/badge/license-MIT-green.svg?style=flat-square | ||
[license-url]: LICENSE | ||
[david-img]: https://img.shields.io/david/koa-modules/koa-methodoverride.svg?style=flat-square | ||
[david-url]: https://david-dm.org/koa-modules/koa-methodoverride |
var koa = require('koa'); | ||
var parse = require('co-body'); | ||
var methodOverride = require('..') | ||
var request = require('supertest'); | ||
var app = koa(); | ||
app.use(function *(next) { | ||
try { | ||
this.request.body = yield parse(this); | ||
} catch (e) { | ||
this.request.body = null; | ||
} | ||
yield next; | ||
}); | ||
app.use(require('../')()); | ||
app.use(function *() { | ||
this.body = this.request.method; | ||
}); | ||
var request = require('supertest').agent(app.listen()); | ||
describe('methodOverride()', function(){ | ||
describe('methodOverride(getter)', function(){ | ||
it('should not touch the method by default', function(done){ | ||
request | ||
var server = createServer() | ||
request(server) | ||
.get('/') | ||
@@ -30,6 +14,6 @@ .expect('GET', done); | ||
it('should be case in-sensitive', function(done){ | ||
request | ||
it('should use X-HTTP-Method-Override by default', function(done){ | ||
var server = createServer() | ||
request(server) | ||
.post('/') | ||
.set('Content-Type', 'application/x-www-form-urlencoded') | ||
.set('X-HTTP-Method-Override', 'DELETE') | ||
@@ -39,9 +23,161 @@ .expect('DELETE', done); | ||
it('should ignore invalid methods', function(done){ | ||
request | ||
.post('/') | ||
.set('Content-Type', 'application/x-www-form-urlencoded') | ||
.set('X-HTTP-Method-Override', 'POST') | ||
.expect('POST', done); | ||
describe('with query', function(){ | ||
it('should work missing query', function(done){ | ||
var server = createServer('_method') | ||
request(server) | ||
.post('/') | ||
.set('Content-Type', 'application/json') | ||
.expect('POST', done); | ||
}) | ||
it('should be case in-sensitive', function(done){ | ||
var server = createServer('_method') | ||
request(server) | ||
.post('/?_method=DElete') | ||
.set('Content-Type', 'application/json') | ||
.expect('DELETE', done); | ||
}) | ||
it('should handle key referencing array', function(done){ | ||
var server = createServer('_method') | ||
var test = request(server).post('/') | ||
test.request().path += '?_method=DELETE&_method=PUT' // supertest mangles query params | ||
test.set('Content-Type', 'application/json') | ||
test.expect('DELETE', done) | ||
}) | ||
it('should only work with POST', function(done){ | ||
var server = createServer('_method') | ||
request(server) | ||
.delete('/?_method=PATCH') | ||
.set('Content-Type', 'application/json') | ||
.expect('DELETE', done) | ||
}) | ||
}) | ||
describe('with header', function(){ | ||
var server | ||
before(function () { | ||
server = createServer('X-HTTP-Method-Override') | ||
}) | ||
it('should work missing header', function(done){ | ||
request(server) | ||
.post('/') | ||
.set('Content-Type', 'application/json') | ||
.expect('POST', done) | ||
}) | ||
it('should be case in-sensitive', function(done){ | ||
request(server) | ||
.post('/') | ||
.set('Content-Type', 'application/json') | ||
.set('X-HTTP-Method-Override', 'DELete') | ||
.expect('DELETE', done) | ||
}) | ||
it('should ignore invalid methods', function(done){ | ||
request(server) | ||
.post('/') | ||
.set('Content-Type', 'application/json') | ||
.set('X-HTTP-Method-Override', 'BOGUS') | ||
.expect('POST', done) | ||
}) | ||
it('should handle multiple headers', function(done){ | ||
request(server) | ||
.post('/') | ||
.set('Content-Type', 'application/json') | ||
.set('X-HTTP-Method-Override', 'DELETE, PUT') | ||
.expect('DELETE', done) | ||
}) | ||
it('should set Vary header', function(done){ | ||
request(server) | ||
.post('/') | ||
.set('Content-Type', 'application/json') | ||
.set('X-HTTP-Method-Override', 'DELETE') | ||
.expect('Vary', 'X-HTTP-Method-Override') | ||
.expect('DELETE', done) | ||
}) | ||
it('should set Vary header even with no override', function(done){ | ||
request(server) | ||
.post('/') | ||
.set('Content-Type', 'application/json') | ||
.expect('Vary', 'X-HTTP-Method-Override') | ||
.expect('POST', done) | ||
}) | ||
}) | ||
describe('with function', function(){ | ||
var server | ||
before(function () { | ||
server = createServer(function(req){ | ||
return req.headers['x-method-override'] || 'PaTcH' | ||
}) | ||
}) | ||
it('should work missing header', function(done){ | ||
request(server) | ||
.post('/') | ||
.set('Content-Type', 'application/json') | ||
.expect('PATCH', done) | ||
}) | ||
it('should be case in-sensitive', function(done){ | ||
request(server) | ||
.post('/') | ||
.set('Content-Type', 'application/json') | ||
.set('X-Method-Override', 'DELete') | ||
.expect('DELETE', done) | ||
}) | ||
it('should ignore invalid methods', function(done){ | ||
request(server) | ||
.post('/') | ||
.set('Content-Type', 'application/json') | ||
.set('X-Method-Override', 'BOGUS') | ||
.expect('POST', done) | ||
}) | ||
}) | ||
describe('given "options.methods"', function(){ | ||
it('should allow other methods', function(done){ | ||
var server = createServer('X-HTTP-Method-Override', { methods: ['POST', 'PATCH'] }) | ||
request(server) | ||
.patch('/') | ||
.set('Content-Type', 'application/json') | ||
.set('X-HTTP-Method-Override', 'DELETE') | ||
.expect('DELETE', done) | ||
}) | ||
it('should allow all methods', function(done){ | ||
var server = createServer('X-HTTP-Method-Override', { methods: null }) | ||
request(server) | ||
.patch('/') | ||
.set('Content-Type', 'application/json') | ||
.set('X-HTTP-Method-Override', 'DELETE') | ||
.expect('DELETE', done) | ||
}) | ||
it('should not call getter when method not allowed', function(done){ | ||
var server = createServer(function(req){ return 'DELETE' }) | ||
request(server) | ||
.patch('/') | ||
.set('Content-Type', 'application/json') | ||
.expect('PATCH', done) | ||
}) | ||
}) | ||
}) | ||
function createServer(getter, opts, fn) { | ||
var app = koa(); | ||
fn && app.use(fn); | ||
app.use(methodOverride(getter,opts)); | ||
app.use(function *() { | ||
this.body = this.request.method; | ||
}); | ||
return app.listen(); | ||
} |
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Wildcard dependency
QualityPackage has a dependency with a floating version range. This can cause issues if the dependency publishes a new major version.
Found 2 instances in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
No bug tracker
MaintenancePackage does not have a linked bug tracker in package.json.
Found 1 instance in 1 package
No repository
Supply chain riskPackage does not have a linked source code repository. Without this field, a package will have no reference to the location of the source code use to generate the package.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
11310
267
50
2
2
3
1
1
+ Addeddebug@*
+ Addeddebug@4.3.7(transitive)
+ Addedmethods@1.1.2(transitive)
+ Addedms@2.1.3(transitive)
- Removedmethods@0.1.0(transitive)
Updatedmethods@*