Skip to content

Commit

Permalink
Forwarding x-forwarded and x-original header to gql response and back…
Browse files Browse the repository at this point in the history
…end requests (#19)

* improves readability of package.json

* adds plugin to append custom headers and x-forwarded header to gql response

* repairs tests after adding custom http header plugins

* attaches x-forwarded or x-original headers to calls to backend

* adds tests for headers that were added to backend calls

* adds tests for http header plugin

* moves http-headers-plugin out to instantiating client

* cleans up params in instantiation of Apollo Server

* Refactoring headers and body processing, Improving unit test for get-body-headers

* Fixing linting issue

* Removing inline comments

* Minor version up to 1.0.9

Co-authored-by: nischal.bachu <[email protected]>
Co-authored-by: Osvaldo Aguilar Lauzurique <[email protected]>
  • Loading branch information
3 people authored Sep 13, 2021
1 parent fea6656 commit 83360b4
Show file tree
Hide file tree
Showing 6 changed files with 90 additions and 45 deletions.
6 changes: 2 additions & 4 deletions helpers/callbackend.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,8 @@ module.exports = async ({ context: { req }, requestOptions }) => {
if (!req) {
throw new Error('Request data is not available')
}
// Reading the headers Out of the context since it is not passed automatically
const { headers: { authorization } } = req
const headers = { authorization }
const bodyAndHeaders = getBodyAndHeaders(body, bodyType, headers)

const bodyAndHeaders = getBodyAndHeaders(body, bodyType, req.headers)

const response = await fetch(url, {
method,
Expand Down
19 changes: 15 additions & 4 deletions helpers/get-body-headers.js
Original file line number Diff line number Diff line change
@@ -1,22 +1,33 @@
const { URLSearchParams } = require('url')

const HEADERS_TO_PROXY = ['authorization', 'x-forwarded', 'x-original']
module.exports = (body, bodyType, headers) => {
const headersToProxy = {}
if (headers) {
Object.entries(headers).forEach(([key, value]) => {
for (const header of HEADERS_TO_PROXY) {
if (key.indexOf(header) !== -1) {
headersToProxy[key] = value
}
}
})
}

if (!body) {
return { headers }
return { headers: headersToProxy }
}

if (bodyType === 'json') {
return {
headers: {
'Content-Type': 'application/json',
...headers
...headersToProxy
},
body: JSON.stringify(body)
}
}

return {
headers,
headers: headersToProxy,
body: new URLSearchParams(body)
}
}
52 changes: 26 additions & 26 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,11 +1,35 @@
{
"name": "gql-gateway",
"description": "GraphQL Gateway that does magic on top of REST services that provides Swagger/OpenAPI specifications.",
"keywords": [
"graphql",
"gateway",
"swagger"
],
"version": "1.0.9",
"license": "MIT",
"author": {
"name": "Ivan Martinez Pupo",
"email": "[email protected]"
},
"homepage": "https://github.com/segpacto/gql-gateway#readme",
"repository": {
"type": "git",
"url": "git+ssh://[email protected]/segpacto/gql-gateway.git"
},
"bugs": {
"url": "https://github.com/segpacto/gql-gateway/issues"
},
"files": [
"index.js",
"helpers"
],
"main": "index.js",
"scripts": {
"lint:fix": "npx standard --fix",
"lint": "npx standard",
"test": "jest --coverage --detectOpenHandles --runInBand --testRegex=test/.*\\.spec\\.js --testPathIgnorePatterns=test/mocks/*.js"
},
"dependencies": {
"apollo-server": "^2.9.16",
"graphql": "^14.5.8",
Expand All @@ -14,7 +38,6 @@
"swagger-to-graphql": "^4.0.2",
"node-fetch": "^2.6.0"
},
"description": "GraphQL Gateway that does magic on top of REST services that provides Swagger/OpenAPI specifications.",
"devDependencies": {
"apollo-server-testing": "^2.9.16",
"dotenv": "^8.2.0",
Expand All @@ -23,32 +46,9 @@
"nodemon": "^2.0.2",
"standard": "^14.3.1"
},
"homepage": "https://github.com/segpacto/gql-gateway#readme",
"keywords": [
"graphql",
"gateway",
"swagger"
],
"license": "MIT",
"main": "index.js",
"name": "gql-gateway",
"repository": {
"type": "git",
"url": "git+ssh://[email protected]/segpacto/gql-gateway.git"
},
"files": [
"index.js",
"helpers"
],
"scripts": {
"lint:fix": "npx standard --fix",
"lint": "npx standard",
"test": "jest --coverage --detectOpenHandles --runInBand --testRegex=test/.*\\.spec\\.js --testPathIgnorePatterns=test/mocks/*.js"
},
"standard": {
"env": [
"jest"
]
},
"version": "1.0.8"
}
}
}
2 changes: 1 addition & 1 deletion test/construct.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ describe('Server construct', () => {
await gateway({ endpointsList })
} catch (err) {
expect(err.code).toBe('ENOTFOUND')
expect(err.message).toBe('request to https://no-existent-endpoint/swagger.json failed, reason: getaddrinfo ENOTFOUND no-existent-endpoint no-existent-endpoint:443')
expect(err.message).toBe('request to https://no-existent-endpoint/swagger.json failed, reason: getaddrinfo ENOTFOUND no-existent-endpoint')
}
})

Expand Down
18 changes: 18 additions & 0 deletions test/unit/helpers/callbackend.spec.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
const callbackend = require('./../../../helpers/callbackend')
require('./../../mocks/gql-gateway-requests')
const nock = require('nock')

describe('callbackend', () => {
it('throw error when no req is attached to context', async () => {
Expand Down Expand Up @@ -27,4 +28,21 @@ describe('callbackend', () => {
expect(err.message).toBe('request to http://localhost/client-api/client?=with-error failed, reason: Whatever error')
}
})

it('x-headers on backend requests should be preserved', async () => {
const context = { req: { headers: { authorization: 'Bearer XXXXX', 'x-forwarded-host': 'http://gql-gateway-test.com', 'x-original-forwarded-for': '88.88.88.88' } } }
const requestOptions = { baseUrl: 'http://localhost', path: '/headers' }
const scope = nock('http://localhost')
.get('/headers')
.reply(200)
.persist()

scope.on('request', function (req, interceptor, body) {
expect(req.headers).toMatchObject({
'x-forwarded-host': ['http://gql-gateway-test.com'],
'x-original-forwarded-for': ['88.88.88.88']
})
})
await callbackend({ context, requestOptions })
})
})
38 changes: 28 additions & 10 deletions test/unit/helpers/get-body-headers.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,22 +2,40 @@ const getBodyHeaders = require('./../../../helpers/get-body-headers')
const { URLSearchParams } = require('url')

describe('get body and headers', () => {
it('return headers only when no body occurs', () => {
expect(getBodyHeaders(undefined, undefined, { test: 'test' })).toStrictEqual({ headers: { test: 'test' } })
expect(getBodyHeaders({ test: 'my-body' }, 'json', { test: 'test' })).toStrictEqual(
it('return only headers when no body occurs', () => {
expect(getBodyHeaders(undefined, undefined, { 'x-forwarded-port': 8080 })).toStrictEqual({ headers: { 'x-forwarded-port': 8080 } })
})

it('should return headers and body with json Content-Type', () => {
expect(getBodyHeaders({ test: 'my-body' }, 'json', { authorization: 'api-key some-key', 'x-forwarded-port': 8080 })).toStrictEqual(
{
headers: {
'Content-Type': 'application/json',
test: 'test'
authorization: 'api-key some-key',
'x-forwarded-port': 8080
},
body: JSON.stringify({ test: 'my-body' })
}
)
})
expect(getBodyHeaders({ test: 'my-body' }, 'application/xml', { test: 'test' })).toStrictEqual(
{
headers: { test: 'test' },
body: new URLSearchParams({ test: 'my-body' })
}
)

it('should return headers and URLSearchParams', () => {
expect(getBodyHeaders({ test: 'my-body' }, 'application/xml', { 'x-forwarded-host': 'http://gql-gateway-test.com' })).toStrictEqual(
{
headers: {
'x-forwarded-host': 'http://gql-gateway-test.com'
},
body: new URLSearchParams({ test: 'my-body' })
}
)
})

it('It should proxy only headers to proxy', () => {
expect(getBodyHeaders({ test: 'my-body' }, 'application/xml', { test: 'test', 'x-forwarded-host': 'http://gql-gateway-test.com' })).toStrictEqual(
{
headers: { 'x-forwarded-host': 'http://gql-gateway-test.com' },
body: new URLSearchParams({ test: 'my-body' })
}
)
})
})

0 comments on commit 83360b4

Please sign in to comment.