From a6cd96f5caa083912ca5334bedbccde1f49489b9 Mon Sep 17 00:00:00 2001 From: DoctorVoid Date: Sun, 16 Jun 2019 12:32:19 +0300 Subject: [PATCH] feat: add polaris headers support in response auto generate uuid for request id if not sent remove event-kind unused request header change upn to oicd-claim-upn --- package-lock.json | 49 +++++++--------- package.json | 1 + src/http/request/polaris-request-headers.ts | 14 +++-- src/server/graphql-server.ts | 6 +- src/server/response-headers-extension.ts | 30 ++++++++++ .../request/polaris-request-headers.test.ts | 57 +++++++------------ 6 files changed, 85 insertions(+), 72 deletions(-) create mode 100644 src/server/response-headers-extension.ts diff --git a/package-lock.json b/package-lock.json index ea4f1a7..8919308 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1260,6 +1260,14 @@ } } }, + "@bitjourney/uuid-v4": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@bitjourney/uuid-v4/-/uuid-v4-1.0.1.tgz", + "integrity": "sha512-CGhPu8xMZwOC5GKjmde33z7Agfap1xEwvi0nvfqNtaXHh38Gjhid0CVLen4TZWBBMCqwyM/Wi2ugVrTV4O2iOw==", + "requires": { + "tslib": "*" + } + }, "@cnakazawa/watch": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/@cnakazawa/watch/-/watch-1.0.3.tgz", @@ -5090,8 +5098,7 @@ "ansi-regex": { "version": "2.1.1", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "aproba": { "version": "1.2.0", @@ -5112,14 +5119,12 @@ "balanced-match": { "version": "1.0.0", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "brace-expansion": { "version": "1.1.11", "bundled": true, "dev": true, - "optional": true, "requires": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -5134,20 +5139,17 @@ "code-point-at": { "version": "1.1.0", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "concat-map": { "version": "0.0.1", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "console-control-strings": { "version": "1.1.0", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "core-util-is": { "version": "1.0.2", @@ -5264,8 +5266,7 @@ "inherits": { "version": "2.0.3", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "ini": { "version": "1.3.5", @@ -5277,7 +5278,6 @@ "version": "1.0.0", "bundled": true, "dev": true, - "optional": true, "requires": { "number-is-nan": "^1.0.0" } @@ -5292,7 +5292,6 @@ "version": "3.0.4", "bundled": true, "dev": true, - "optional": true, "requires": { "brace-expansion": "^1.1.7" } @@ -5300,14 +5299,12 @@ "minimist": { "version": "0.0.8", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "minipass": { "version": "2.3.5", "bundled": true, "dev": true, - "optional": true, "requires": { "safe-buffer": "^5.1.2", "yallist": "^3.0.0" @@ -5326,7 +5323,6 @@ "version": "0.5.1", "bundled": true, "dev": true, - "optional": true, "requires": { "minimist": "0.0.8" } @@ -5407,8 +5403,7 @@ "number-is-nan": { "version": "1.0.1", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "object-assign": { "version": "4.1.1", @@ -5420,7 +5415,6 @@ "version": "1.4.0", "bundled": true, "dev": true, - "optional": true, "requires": { "wrappy": "1" } @@ -5506,8 +5500,7 @@ "safe-buffer": { "version": "5.1.2", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "safer-buffer": { "version": "2.1.2", @@ -5543,7 +5536,6 @@ "version": "1.0.2", "bundled": true, "dev": true, - "optional": true, "requires": { "code-point-at": "^1.0.0", "is-fullwidth-code-point": "^1.0.0", @@ -5563,7 +5555,6 @@ "version": "3.0.1", "bundled": true, "dev": true, - "optional": true, "requires": { "ansi-regex": "^2.0.0" } @@ -5607,14 +5598,12 @@ "wrappy": { "version": "1.0.2", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "yallist": { "version": "3.0.3", "bundled": true, - "dev": true, - "optional": true + "dev": true } } }, diff --git a/package.json b/package.json index d1f407d..830e978 100644 --- a/package.json +++ b/package.json @@ -65,6 +65,7 @@ }, "homepage": "https://github.com/yarinvak/polaris#readme", "dependencies": { + "@bitjourney/uuid-v4": "^1.0.1", "@enigmatis/polaris-logs": "^2.5.3", "@enigmatis/utills": "^1.3.1", "@types/graphql": "^14.2.0", diff --git a/src/http/request/polaris-request-headers.ts b/src/http/request/polaris-request-headers.ts index 2c36639..620da2e 100644 --- a/src/http/request/polaris-request-headers.ts +++ b/src/http/request/polaris-request-headers.ts @@ -1,3 +1,4 @@ +import { generateUUIDv4 } from '@bitjourney/uuid-v4'; import { PolarisRequestHeaders } from '@enigmatis/utills'; import { UserInputError } from 'apollo-server-koa'; import * as joi from 'joi'; @@ -8,8 +9,7 @@ const headersSchema = joi.object().keys({ 'include-linked-oper': joi.boolean(), 'snap-page-size': joi.number(), 'request-id': joi.string(), - upn: joi.string(), - 'event-kind': joi.string(), + 'oicd-claim-upn': joi.string(), 'reality-id': joi.number(), 'requesting-sys': joi.string(), 'requesting-sys-name': joi.string(), @@ -22,14 +22,18 @@ export const getHeaders = (candidate: object): PolarisRequestHeaders => { if (error) { throw new UserInputError(error.message); } else { + let requestId = validatedHeaders['request-id']; + if (requestId === undefined) { + requestId = generateUUIDv4(); + } + return { dataVersion: validatedHeaders['data-version'], isSnapshot: validatedHeaders['snap-request'], includeLinkedOperation: validatedHeaders['include-linked-oper'], snapshotPageSize: validatedHeaders['snap-page-size'], - requestId: validatedHeaders['request-id'], - upn: validatedHeaders.upn, - eventKind: validatedHeaders['event-kind'], + requestId, + upn: validatedHeaders['oicd-claim-upn'], realityId: validatedHeaders['reality-id'], requestingSystemId: validatedHeaders['requesting-sys'], requestingSystemName: validatedHeaders['requesting-sys-name'], diff --git a/src/server/graphql-server.ts b/src/server/graphql-server.ts index 4f07391..cd27260 100644 --- a/src/server/graphql-server.ts +++ b/src/server/graphql-server.ts @@ -15,6 +15,7 @@ import { createMiddleware } from '../middlewares/polaris-middleware-creator'; import { PolarisProperties } from '../properties/polaris-properties'; import { IrrelevantEntitiesExtension } from './irrelevant-entities-extension'; import { PolarisContext } from './polaris-context'; +import { ResponseHeadersExtension } from './response-headers-extension'; export interface GraphQLServer { server: ApolloServer; @@ -51,7 +52,10 @@ export class PolarisGraphQLServer implements GraphQLServer { context: (args: { ctx: Koa.Context; connection: any }) => this.getContext(args), formatError: (error: any) => this.formatError(error), formatResponse: (response: any) => this.formatResponse(response), - extensions: [() => new IrrelevantEntitiesExtension()], + extensions: [ + () => new IrrelevantEntitiesExtension(), + () => new ResponseHeadersExtension(), + ], }; this.server = new ApolloServer(config); this.app = new Koa(); diff --git a/src/server/response-headers-extension.ts b/src/server/response-headers-extension.ts new file mode 100644 index 0000000..e9e2213 --- /dev/null +++ b/src/server/response-headers-extension.ts @@ -0,0 +1,30 @@ +import { GraphQLExtension, GraphQLResponse } from 'graphql-extensions'; +import { PolarisContext } from './polaris-context'; + +export const requestIdHeaderName: string = 'Request-Id'; +export const oicdClaimUpnHeaderName: string = 'Oicd-Claim-Upn'; +export const realityIdHeaderName: string = 'Reality-Id'; + +export class ResponseHeadersExtension extends GraphQLExtension { + willSendResponse(responseContext: { + graphqlResponse: GraphQLResponse; + context: PolarisContext; + }) { + const { context, graphqlResponse } = responseContext; + if (graphqlResponse.http && graphqlResponse.http.headers) { + const headers = []; + if (context.headers.requestId !== undefined) { + headers.push([requestIdHeaderName, context.headers.requestId]); + } + if (context.headers.upn !== undefined) { + headers.push([oicdClaimUpnHeaderName, context.headers.upn]); + } + if (context.headers.realityId !== undefined) { + headers.push([realityIdHeaderName, context.headers.realityId]); + } + // @ts-ignore + graphqlResponse.http = { headers }; + } + return responseContext; + } +} diff --git a/test/http/request/polaris-request-headers.test.ts b/test/http/request/polaris-request-headers.test.ts index cb507d2..3bd10f8 100644 --- a/test/http/request/polaris-request-headers.test.ts +++ b/test/http/request/polaris-request-headers.test.ts @@ -1,15 +1,15 @@ -import { getHeaders } from '../../../src/http/request/polaris-request-headers'; +import {getHeaders} from '../../../src/http/request/polaris-request-headers'; describe('polaris-request-headers tests', () => { describe('data version header', () => { test('numeral header', () => { - const headers = { 'data-version': 500 }; + const headers = {'data-version': 500}; const polarisRequestHeaders = getHeaders(headers); expect(polarisRequestHeaders.dataVersion).toBe(headers['data-version']); }); test('not numeral header', () => { - const headers = { 'data-version': 'wow' }; + const headers = {'data-version': 'wow'}; expect(() => { getHeaders(headers); }).toThrowError('must be a number'); @@ -18,13 +18,13 @@ describe('polaris-request-headers tests', () => { describe('snap request header', () => { test('boolean header', () => { - const headers = { 'snap-request': true }; + const headers = {'snap-request': true}; const polarisRequestHeaders = getHeaders(headers); expect(polarisRequestHeaders.isSnapshot).toBe(headers['snap-request']); }); test('not boolean header', () => { - const headers = { 'snap-request': 'wow' }; + const headers = {'snap-request': 'wow'}; expect(() => { getHeaders(headers); }).toThrowError('must be a boolean'); @@ -33,7 +33,7 @@ describe('polaris-request-headers tests', () => { describe('include linked oper header', () => { test('boolean header', () => { - const headers = { 'include-linked-oper': true }; + const headers = {'include-linked-oper': true}; const polarisRequestHeaders = getHeaders(headers); expect(polarisRequestHeaders.includeLinkedOperation).toBe( headers['include-linked-oper'], @@ -41,7 +41,7 @@ describe('polaris-request-headers tests', () => { }); test('not boolean header', () => { - const headers = { 'include-linked-oper': 'wow' }; + const headers = {'include-linked-oper': 'wow'}; expect(() => { getHeaders(headers); }).toThrowError('must be a boolean'); @@ -50,13 +50,13 @@ describe('polaris-request-headers tests', () => { describe('snap page size header', () => { test('numeral header', () => { - const headers = { 'snap-page-size': 55 }; + const headers = {'snap-page-size': 55}; const polarisRequestHeaders = getHeaders(headers); expect(polarisRequestHeaders.snapshotPageSize).toBe(headers['snap-page-size']); }); test('not numeral header', () => { - const headers = { 'snap-page-size': 'wow' }; + const headers = {'snap-page-size': 'wow'}; expect(() => { getHeaders(headers); }).toThrowError('must be a number'); @@ -65,43 +65,28 @@ describe('polaris-request-headers tests', () => { describe('request-id header', () => { test('string header', () => { - const headers = { 'request-id': 'wow' }; + const headers = {'request-id': 'wow'}; const polarisRequestHeaders = getHeaders(headers); expect(polarisRequestHeaders.requestId).toBe(headers['request-id']); }); test('not string header', () => { - const headers = { 'request-id': 55 }; + const headers = {'request-id': 55}; expect(() => { getHeaders(headers); }).toThrowError('must be a string'); }); }); - describe('upn header', () => { + describe('oicd-claim-upn header', () => { test('string header', () => { - const headers = { upn: 'wow' }; + const headers = {'oicd-claim-upn': 'wow'}; const polarisRequestHeaders = getHeaders(headers); - expect(polarisRequestHeaders.upn).toBe(headers.upn); + expect(polarisRequestHeaders.upn).toBe(headers['oicd-claim-upn']); }); test('not string header', () => { - const headers = { upn: 55 }; - expect(() => { - getHeaders(headers); - }).toThrowError('must be a string'); - }); - }); - - describe('event kind header', () => { - test('string header', () => { - const headers = { 'event-kind': 'wow' }; - const polarisRequestHeaders = getHeaders(headers); - expect(polarisRequestHeaders.eventKind).toBe(headers['event-kind']); - }); - - test('not string header', () => { - const headers = { 'event-kind': 55 }; + const headers = {'oicd-claim-upn': 55}; expect(() => { getHeaders(headers); }).toThrowError('must be a string'); @@ -110,13 +95,13 @@ describe('polaris-request-headers tests', () => { describe('reality id header', () => { test('number header', () => { - const headers = { 'reality-id': 55 }; + const headers = {'reality-id': 55}; const polarisRequestHeaders = getHeaders(headers); expect(polarisRequestHeaders.realityId).toBe(headers['reality-id']); }); test('not number header', () => { - const headers = { 'reality-id': 'wow' }; + const headers = {'reality-id': 'wow'}; expect(() => { getHeaders(headers); }).toThrowError('must be a number'); @@ -125,13 +110,13 @@ describe('polaris-request-headers tests', () => { describe('requesting sys header', () => { test('string header', () => { - const headers = { 'requesting-sys': 'wow' }; + const headers = {'requesting-sys': 'wow'}; const polarisRequestHeaders = getHeaders(headers); expect(polarisRequestHeaders.requestingSystemId).toBe(headers['requesting-sys']); }); test('not string header', () => { - const headers = { 'requesting-sys': 55 }; + const headers = {'requesting-sys': 55}; expect(() => { getHeaders(headers); }).toThrowError('must be a string'); @@ -140,13 +125,13 @@ describe('polaris-request-headers tests', () => { describe('requesting sys header', () => { test('string header', () => { - const headers = { 'requesting-sys-name': 'wow' }; + const headers = {'requesting-sys-name': 'wow'}; const polarisRequestHeaders = getHeaders(headers); expect(polarisRequestHeaders.requestingSystemName).toBe(headers['requesting-sys-name']); }); test('not string header', () => { - const headers = { 'requesting-sys-name': 55 }; + const headers = {'requesting-sys-name': 55}; expect(() => { getHeaders(headers); }).toThrowError('must be a string');