diff --git a/src/LambdaReq.js b/src/LambdaReq.js index 0fe41d3..d622273 100644 --- a/src/LambdaReq.js +++ b/src/LambdaReq.js @@ -1,6 +1,5 @@ import debug from 'debug' import LambdaReqError from './LambdaReqError' - const log = debug('LambdaReq:') class LambdaReq { @@ -75,6 +74,7 @@ class LambdaReq { console.assert(typeof event === 'object' && event !== null, 'Malformed Lambda event object.') console.assert(typeof callback === 'function', 'Malformed Lambda callback.') + log('handling invocation for route %s', this.currentRoute) @@ -93,7 +93,8 @@ class LambdaReq { const reqData = { params: Object.assign({}, this.params), - headers: this.headers ? Object.assign({}, this.headers) : undefined + headers: this.headers ? Object.assign({}, this.headers) : undefined, + body: this._event.body } let result @@ -103,7 +104,6 @@ class LambdaReq { log('handler %s responded with error: %s', this.currentRoute, err) return this._respond(err) } - if (result && result.then) { log('handling an async result for %s', this.currentRoute) return result.then((res)=> this._respond(null, res)).catch((err)=> this._respond(err)) @@ -126,9 +126,33 @@ class LambdaReq { this._routes[id] = handler } - _parseApiGatewayData (event = this._event) { + _parseApiGatewayBody(event) { const body = {} - Object.assign(body, JSON.parse(event.body)) + const headers = event.headers || {} + const contentType = headers['content-type'] || headers['Content-Type'] || 'application/json' + if (contentType.toLowerCase() === 'application/json') { + Object.assign(body, JSON.parse(event.body || '{}')) + } else if (contentType.toLowerCase() === 'application/x-www-form-urlencoded') { + const pieces = {} + event.body.split('&').forEach(part => { + const keyValue = part.split('=') + pieces[keyValue[0]] = keyValue[1] + }) + Object.assign(body, pieces) + } else if (!/multipart/.test(contentType)) { + try { + Object.assign(body, JSON.parse(event.body)) + } catch(e) { + // + } + } + + return body + } + + _parseApiGatewayData (event = this._event) { + const headers = event.headers || {} + const body = this._parseApiGatewayBody(event) return { method: event.httpMethod, diff --git a/tests/unit/LambdaReq.js b/tests/unit/LambdaReq.js index f555c47..836ac26 100644 --- a/tests/unit/LambdaReq.js +++ b/tests/unit/LambdaReq.js @@ -36,10 +36,10 @@ describe('LambdaReq', () => { const lambda = new LambdaReq(API_GATEWAY_EVENT, {}, callback) lambda.get('/v1/test', handler) lambda.invoke() - should(handler.calledWith( + should(handler.calledWith(sinon.match( { params: { name: 'john', id: 'u-123', active: true }, headers: { 'Content-Type': 'application/json' } - }, + }), lambda )).eql(true) should(callback.getCall(0).args[1]).containEql({ @@ -48,6 +48,26 @@ describe('LambdaReq', () => { }) }) + it('responds to x-www-form-urlencoded', () => { + const callback = sinon.stub() + const handler = sinon.stub().returns({ success: true }) + const event = Object.assign({}, API_GATEWAY_EVENT, { + headers: { + 'Content-Type': 'application/x-www-form-urlencoded', + }, + body: 'active=true' + }) + + const lambda = new LambdaReq(event, {}, callback) + lambda.get('/v1/test', handler) + lambda.invoke() + + should(callback.getCall(0).args[1]).containEql({ + statusCode: 200, + body: '{"success":true}' + }) + }) + describe('when the handler result is a promise', () => { it('waits for the promise to resolve then it responds', () => { const callback = sinon.stub() @@ -56,10 +76,10 @@ describe('LambdaReq', () => { lambda.get('/v1/test', handler) return lambda.invoke() .then(()=> { - should(handler.calledWith( + should(handler.calledWith(sinon.match( { params: { name: 'john', id: 'u-123', active: true }, headers: { 'Content-Type': 'application/json' } - }, + }), lambda )).eql(true) should(callback.getCall(0).args[1]).containEql({ @@ -175,8 +195,8 @@ describe('LambdaReq', () => { const lambda = new LambdaReq(PROXY_EVENT, {}, callback) lambda.proxy('commandName', handler) lambda.invoke() - should(handler.calledWith( - { params: { id: 'u-123' }, headers: undefined }, + should(handler.calledWith(sinon.match( + { params: { id: 'u-123' }, headers: undefined }), lambda )).eql(true) should(callback.getCall(0).args[1]).containEql('{"success":true}')