New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

@middy/http-response-serializer

Package Overview
Dependencies
Maintainers
3
Versions
197
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@middy/http-response-serializer - npm Package Compare versions

Comparing version 1.5.2 to 2.0.0-alpha.0

406

__tests__/index.js

@@ -0,7 +1,9 @@

const test = require('ava')
const sinon = require('sinon')
const middy = require('../../core/index.js')
const createError = require('http-errors')
const { invoke } = require('../../test-helpers')
const middy = require('../../core')
const httpErrorHandler = require('../../http-error-handler')
const httpResponseSerializer = require('../')
const httpErrorHandler = require('../../http-error-handler/index.js')
const httpResponseSerializer = require('../index.js')
const standardConfiguration = {

@@ -30,274 +32,268 @@ serializers: [

describe('📦 Middleware Http Response Serializer', () => {
describe('It should pass-through when `content-type` header is already set', () => {
test.each([
['Content-Type'],
['content-type'],
['CONTENT-TYPE']
])(
'%s skips response serialization',
async (key) => {
const handlerResponse = Object.assign({}, createHttpResponse(), {
headers: {
[key]: 'text/plain'
}
})
const handler = middy((event, context, cb) => cb(null, handlerResponse))
for (const [key] of [
['Content-Type'],
['content-type'],
['CONTENT-TYPE']
]) {
test(`${key} skips response serialization`, async (t) => {
handler.use(httpResponseSerializer(standardConfiguration))
const handlerResponse = Object.assign({}, createHttpResponse(), {
headers: {
[key]: 'text/plain'
}
})
const handler = middy((event, context) => handlerResponse)
const response = await invoke(handler)
handler.use(httpResponseSerializer(standardConfiguration))
expect(response).toEqual(handlerResponse)
})
const response = await handler()
t.is(response, handlerResponse)
})
}
describe('It should find the correct serializer from the request accept header', () => {
test.each([
['application/xml, text/x-dvi; q=0.8, text/x-c', '<message>Hello World</message>'],
['application/json, text/plain, */*', '{"message":"Hello World"}'],
['text/plain, text/x-c', 'Hello World']
])(
'%s returns %s',
async (accept, result) => {
const handler = middy((event, context, cb) => cb(null, createHttpResponse()))
for (const [accept, result] of [
['application/xml, text/x-dvi; q=0.8, text/x-c', '<message>Hello World</message>'],
['text/x-dvi; q=0.8, application/xml, text/x-c', '<message>Hello World</message>'],
['text/x-dvi, application/xml, text/x-c', '<message>Hello World</message>'],
['application/json, text/plain, */*', '{"message":"Hello World"}'],
['*/*', '{"message":"Hello World"}'],
['text/x-dvi, */*', '{"message":"Hello World"}'],
['text/plain, text/x-c', 'Hello World']
]) {
test(`${accept} returns ${result}`, async (t) => {
const handler = middy((event, context) => createHttpResponse())
handler.use(httpResponseSerializer(standardConfiguration))
handler.use(httpResponseSerializer(standardConfiguration))
const event = {
headers: {
Accept: accept
}
}
const event = {
headers: {
Accept: accept
}
}
const response = await invoke(handler, event)
const response = await handler(event)
expect(response.body).toEqual(result)
})
t.is(response.body, result)
})
}
test('It should use `event.requiredContentType` instead of accept headers', async () => {
const handler = middy((event, context, cb) => {
event.requiredContentType = 'text/plain'
test('It should use `event.requiredContentType` instead of accept headers', async (t) => {
const handler = middy((event, context) => {
event.requiredContentType = 'text/plain'
cb(null, createHttpResponse())
})
return createHttpResponse()
})
handler.use(httpResponseSerializer(standardConfiguration))
handler.use(httpResponseSerializer(standardConfiguration))
const event = {
headers: {
Accept: 'application/xml, text/x-dvi; q=0.8, text/x-c'
}
const event = {
headers: {
Accept: 'application/xml, text/x-dvi; q=0.8, text/x-c'
}
}
const response = await invoke(handler, event)
const response = await handler(event)
expect(response).toEqual({
statusCode: 200,
headers: {
'Content-Type': 'text/plain'
},
body: 'Hello World'
})
t.deepEqual(response, {
statusCode: 200,
headers: {
'Content-Type': 'text/plain'
},
body: 'Hello World'
})
})
test('It should use the default when no accept preferences are given', async () => {
const handler = middy((event, context, cb) =>
cb(null, createHttpResponse())
)
test('It should use the default when no accept preferences are given', async (t) => {
const handler = middy((event, context) => createHttpResponse()
)
handler.use(httpResponseSerializer(standardConfiguration))
handler.use(httpResponseSerializer(standardConfiguration))
const response = await invoke(handler)
const response = await handler()
expect(response).toEqual({
statusCode: 200,
headers: {
'Content-Type': standardConfiguration.default
},
body: '{"message":"Hello World"}'
})
t.deepEqual(response, {
statusCode: 200,
headers: {
'Content-Type': standardConfiguration.default
},
body: '{"message":"Hello World"}'
})
})
test('It should use the default when no matching accept preferences are found', async () => {
const handler = middy((event, context, cb) => {
event.preferredContentType = 'text/java'
test('It should use the default when no matching accept preferences are found', async (t) => {
const handler = middy((event, context) => {
event.preferredContentType = 'text/java'
cb(null, createHttpResponse())
})
return createHttpResponse()
})
handler.use(httpResponseSerializer(standardConfiguration))
handler.use(httpResponseSerializer(standardConfiguration))
const event = {
headers: {
Accept: 'application/java, text/x-dvi; q=0.8, text/x-c'
}
const event = {
headers: {
Accept: 'application/java, text/x-dvi; q=0.8, text/x-c'
}
}
const response = await invoke(handler, event)
const response = await handler(event)
expect(response).toEqual({
statusCode: 200,
headers: {
'Content-Type': standardConfiguration.default
},
body: '{"message":"Hello World"}'
})
t.deepEqual(response, {
statusCode: 200,
headers: {
'Content-Type': standardConfiguration.default
},
body: '{"message":"Hello World"}'
})
})
test('It should use `event.preferredContentType` instead of the default', async () => {
const handler = middy((event, context, cb) => {
event.preferredContentType = 'text/plain'
test('It should use `event.preferredContentType` instead of the default', async (t) => {
const handler = middy((event, context) => {
event.preferredContentType = 'text/plain'
cb(null, createHttpResponse())
})
return createHttpResponse()
})
handler.use(httpResponseSerializer(standardConfiguration))
handler.use(httpResponseSerializer(standardConfiguration))
const response = await invoke(handler)
const response = await handler()
expect(response).toEqual({
statusCode: 200,
headers: {
'Content-Type': 'text/plain'
},
body: 'Hello World'
})
t.deepEqual(response, {
statusCode: 200,
headers: {
'Content-Type': 'text/plain'
},
body: 'Hello World'
})
})
test('It should pass-through when no preference or default is found', async () => {
const handler = middy((event, context, cb) =>
cb(null, createHttpResponse())
)
test('It should pass-through when no preference or default is found', async (t) => {
const handler = middy((event, context) => createHttpResponse()
)
handler.use(httpResponseSerializer({
serializers: standardConfiguration.serializers
}))
handler.use(httpResponseSerializer({
serializers: standardConfiguration.serializers
}))
const response = await invoke(handler)
const response = await handler()
expect(response).toEqual({
statusCode: 200,
body: 'Hello World'
})
t.deepEqual(response, {
statusCode: 200,
body: 'Hello World'
})
})
test('It should not pass-through when request content-type is set', async () => {
const handler = middy((event, context, cb) =>
cb(null, createHttpResponse())
)
test('It should not pass-through when request content-type is set', async (t) => {
const handler = middy((event, context) => createHttpResponse()
)
handler.use(httpResponseSerializer(standardConfiguration))
handler.use(httpResponseSerializer(standardConfiguration))
const event = {
headers: {
'Content-Type': 'application/xml'
}
const event = {
headers: {
'Content-Type': 'application/xml'
}
}
const response = await invoke(handler, event)
const response = await handler(event)
expect(response).toEqual({
statusCode: 200,
headers: {
'Content-Type': standardConfiguration.default
},
body: '{"message":"Hello World"}'
})
t.deepEqual(response, {
statusCode: 200,
headers: {
'Content-Type': standardConfiguration.default
},
body: '{"message":"Hello World"}'
})
})
test('It should replace the response object when the serializer returns an object', async () => {
const handler = middy((event, context, cb) =>
cb(null, createHttpResponse())
)
test('It should replace the response object when the serializer returns an object', async (t) => {
const handler = middy((event, context) => createHttpResponse()
)
handler.use(httpResponseSerializer({
serializers: [
{
regex: /^text\/plain$/,
serializer: (response) => (Object.assign({}, response, {
body: Buffer.from(response.body).toString('base64'),
isBase64Encoded: true
}))
}
],
default: 'text/plain'
}))
handler.use(httpResponseSerializer({
serializers: [
{
regex: /^text\/plain$/,
serializer: (response) => (Object.assign({}, response, {
body: Buffer.from(response.body).toString('base64'),
isBase64Encoded: true
}))
}
],
default: 'text/plain'
}))
const response = await invoke(handler)
const response = await handler()
expect(response).toEqual({
statusCode: 200,
headers: {
'Content-Type': 'text/plain'
},
body: 'SGVsbG8gV29ybGQ=',
isBase64Encoded: true
})
t.deepEqual(response, {
statusCode: 200,
headers: {
'Content-Type': 'text/plain'
},
body: 'SGVsbG8gV29ybGQ=',
isBase64Encoded: true
})
})
test('It should work with `http-error-handler` middleware', async () => {
const handler = middy((event, context, cb) => {
throw new createError.UnprocessableEntity()
})
test('It should work with `http-error-handler` middleware', async (t) => {
const handler = middy((event, context) => {
throw new createError.UnprocessableEntity()
})
handler
.use(httpErrorHandler())
.use(httpResponseSerializer(standardConfiguration))
handler
.use(httpResponseSerializer(standardConfiguration))
.use(httpErrorHandler({logger:false}))
const response = await invoke(handler)
const response = await handler()
expect(response).toEqual({
statusCode: 422,
body: '{"message":"Unprocessable Entity"}',
headers: {
'Content-Type': 'application/json'
}
})
t.deepEqual(response, {
statusCode: 422,
body: 'Unprocessable Entity',
headers: {
'Content-Type': 'plain/text'
}
})
})
test('It should not crash if the response is undefined', async () => {
const handler = middy((event, context, cb) =>
cb(null, undefined)
)
test('It should not crash if the response is undefined', async (t) => {
const handler = middy((event, context) => undefined)
handler.use(httpResponseSerializer(standardConfiguration))
handler.use(httpResponseSerializer(standardConfiguration))
const event = {
headers: {
'Content-Type': 'application/xml'
}
const event = {
headers: {
'Content-Type': 'application/xml'
}
}
const response = await invoke(handler, event)
const response = await handler(event)
expect(response).toEqual({
headers: {
'Content-Type': standardConfiguration.default
},
body: '{}'
})
t.deepEqual(response, {
headers: {
'Content-Type': standardConfiguration.default
},
body: '{}'
})
})
test('It should return false when response body is falsey', async () => {
const handler = middy((event, context, cb) => {
cb(null, false)
})
test('It should return false when response body is falsey', async (t) => {
const handler = middy((event, context) => {
return false
})
const event = {
headers: {
Accept: 'text/plain'
}
const event = {
headers: {
Accept: 'text/plain'
}
handler.use(httpResponseSerializer(standardConfiguration))
const response = await invoke(handler, event)
}
handler.use(httpResponseSerializer(standardConfiguration))
const response = await handler(event)
expect(response).toEqual({
headers: {
'Content-Type': 'text/plain'
},
body: false
})
t.deepEqual(response, {
headers: {
'Content-Type': 'text/plain'
},
body: false
})
})

@@ -1,73 +0,76 @@

const Accept = require('@hapi/accept')
const Accept = require('@hapi/accept');
const getNormalisedHeaders = (source) => Object
.keys(source)
.reduce((destination, key) => {
destination[key.toLowerCase()] = source[key]
const defaults = {};
return destination
}, {})
module.exports = (opts = {}) => {
const options = { ...defaults,
...opts
};
const middleware = (opts, handler, next) => {
// normalise headers for internal use only
const requestHeaders = getNormalisedHeaders((handler.event && handler.event.headers) || {})
const responseHeaders = getNormalisedHeaders((handler.response && handler.response.headers) || {})
const httpResponseSerializerMiddlewareAfter = async handler => {
// normalise headers for internal use only
const requestHeaders = getNormalisedHeaders(handler.event?.headers ?? {});
const responseHeaders = getNormalisedHeaders(handler.response?.headers ?? {}); // skip serialization when content-type is already set
// skip serialization when content-type is already set
if (responseHeaders['content-type']) {
return next()
}
if (responseHeaders['content-type']) {
return;
} // find accept value(s)
// find accept value(s)
let types
if (handler.event.requiredContentType) {
types = [].concat(handler.event.requiredContentType)
} else {
types = [].concat(
(requestHeaders.accept && Accept.mediaTypes(requestHeaders.accept)) || [],
handler.event.preferredContentType || [],
opts.default || []
)
}
let types;
const handlerEvent = handler.event;
// dont bother finding a serializer if no types are given
if (!types.length) {
return next()
}
if (handlerEvent?.requiredContentType) {
types = [].concat(handlerEvent.requiredContentType);
} else {
types = [].concat(requestHeaders.accept && Accept.mediaTypes(requestHeaders.accept) || [], handlerEvent.preferredContentType || [], options.default || []);
} // dont bother finding a serializer if no types are given
// find in order of first preferred type that has a matching serializer
types.find(type => opts.serializers.find(s => {
const test = s.regex.test(type)
if (!test) { return false }
if (!types.length) {
return;
} // find in order of first preferred type that has a matching serializer
// if the response is not an object, assign it to body. { body: undefined } is not serialized
handler.response = typeof handler.response === 'object' ? handler.response : { body: handler.response }
// set header
handler.response.headers = Object.assign({}, handler.response.headers, { 'Content-Type': type })
types.find(type => options.serializers.find(s => {
const test = s.regex.test(type);
// run serializer
const result = s.serializer(handler.response)
if (!test) {
return false;
} // if the response is not an object, assign it to body. { body: undefined } is not serialized
if (typeof result === 'object') {
// replace response object if result is object
handler.response = result
} else {
// otherwise only replace the body attribute
handler.response.body = result
}
return true
}))
handler.response = handler.response !== null && typeof handler.response === 'object' ? handler.response : {
body: handler.response
}; // set header
next()
}
handler.response.headers = handler.response?.headers ?? {};
handler.response.headers = { ...handler.response.headers,
'Content-Type': type
}; // run serializer
module.exports = opts => {
const result = s.serializer(handler.response);
if (typeof result === 'object') {
// replace response object if result is object
handler.response = result;
} else {
// otherwise only replace the body attribute
handler.response.body = result;
}
return true;
}));
};
const httpResponseSerializerMiddlewareOnError = httpResponseSerializerMiddlewareAfter;
return {
after: (handler, next) => middleware(opts, handler, next),
onError: (handler, next) => middleware(opts, handler, next)
}
}
after: httpResponseSerializerMiddlewareAfter,
onError: httpResponseSerializerMiddlewareOnError
};
};
const getNormalisedHeaders = source => Object.keys(source).reduce((destination, key) => {
destination[key.toLowerCase()] = source[key];
return destination;
}, {});
{
"name": "@middy/http-response-serializer",
"version": "1.5.2",
"version": "2.0.0-alpha.0",
"description": "The Http Serializer middleware lets you define serialization mechanisms based on the current content negotiation.",
"type": "commonjs",
"engines": {
"node": ">=10"
"node": ">=14"
},

@@ -12,5 +13,7 @@ "engineStrict": true,

},
"main": "index.js",
"types": "index.d.ts",
"scripts": {
"test": "npm run test:typings && npm run test:unit",
"test:unit": "jest",
"test:unit": "ava",
"test:typings": "typings-tester --config tsconfig.json index.d.ts"

@@ -40,3 +43,4 @@ },

"type": "git",
"url": "git+https://github.com/middyjs/middy.git"
"url": "github:middyjs/middy",
"directory": "packages/http-reponse-serializer"
},

@@ -48,13 +52,6 @@ "bugs": {

"dependencies": {
"@hapi/accept": "^5.0.1",
"http-errors": "^1.7.3"
"@hapi/accept": "5.0.1",
"http-errors": "1.8.0"
},
"peerDependencies": {
"@middy/core": ">=1.0.0-alpha"
},
"devDependencies": {
"@middy/core": "^1.5.2",
"es6-promisify": "^6.0.2"
},
"gitHead": "f77cb5e1fc2c529f4fe74efa8a9fb105373b0723"
"gitHead": "e047c0d3db00aa11b39f2d3e193458ea021a58a0"
}
# Middy http-response-serializer middleware
<div align="center">
<img alt="Middy logo" src="https://raw.githubusercontent.com/middyjs/middy/master/img/middy-logo.png"/>
<img alt="Middy logo" src="https://raw.githubusercontent.com/middyjs/middy/master/docs/img/middy-logo.png"/>
</div>

@@ -22,5 +22,2 @@

</a>
<a href="https://greenkeeper.io/">
<img src="https://badges.greenkeeper.io/middyjs/middy.svg" alt="Greenkeeper badge" style="max-width:100%;">
</a>
<a href="https://gitter.im/middyjs/Lobby">

@@ -109,6 +106,6 @@ <img src="https://badges.gitter.im/gitterHQ/gitter.svg" alt="Chat on Gitter" style="max-width:100%;">

```javascript
const middy = require('@middy/core')
const httpResponseSerializer = require('@middy/http-response-serializer')
import middy from '@middy/core'
import httpResponseSerializer from '@middy/http-response-serializer'
const handler = middy((event, context, cb) => {
const handler = middy((event, context) => {
const body = 'Hello World'

@@ -148,3 +145,3 @@

handler(event, {}, (_, response) => {
expect(response.body).toEqual('<message>Hello World</message>')
t.is(response.body,'<message>Hello World</message>')
})

@@ -166,3 +163,3 @@ ```

Licensed under [MIT License](LICENSE). Copyright (c) 2017-2018 Luciano Mammino and the [Middy team](https://github.com/middyjs/middy/graphs/contributors).
Licensed under [MIT License](LICENSE). Copyright (c) 2017-2021 Luciano Mammino, will Farrell, and the [Middy team](https://github.com/middyjs/middy/graphs/contributors).

@@ -169,0 +166,0 @@ <a href="https://app.fossa.io/projects/git%2Bgithub.com%2Fmiddyjs%2Fmiddy?ref=badge_large">

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc