From 60edd7e33bc8d78446c5f6b7911126ddd5d19ffe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bogdan=20St=C4=83ncescu?= Date: Thu, 28 Oct 2021 01:49:20 +0300 Subject: [PATCH] fix!: Add type annotation for Request.rawBody We are store the raw HTTP body on a `rawBody` field of the HTTP Request object. This commit adds a type annotation for it. --- docs/generated/api.d.ts | 21 +++++++++- docs/generated/api.json | 91 ++++++++++++++++++++++++++++++++++++++-- docs/generated/api.md | 14 ++++++- src/functions.ts | 17 +++++++- src/invoker.ts | 11 ----- src/server.ts | 8 +--- test/integration/http.ts | 19 ++++----- 7 files changed, 146 insertions(+), 35 deletions(-) diff --git a/docs/generated/api.d.ts b/docs/generated/api.d.ts index 25051d0f..08980872 100644 --- a/docs/generated/api.d.ts +++ b/docs/generated/api.d.ts @@ -1,3 +1,5 @@ +/// + import * as express from 'express'; /** @@ -149,7 +151,7 @@ export declare const http: (functionName: string, handler: HttpFunction) => void * @public */ export declare interface HttpFunction { - (req: express.Request, res: express.Response): any; + (req: Request_2, res: Response_2): any; } /** @@ -169,4 +171,21 @@ export declare interface LegacyEvent { context: CloudFunctionsContext; } +/** + * @public + */ +declare interface Request_2 extends express.Request { + /** + * A buffer which provides access to the request's raw HTTP body. + */ + rawBody?: Buffer; +} +export { Request_2 as Request } + +/** + * @public + */ +declare type Response_2 = express.Response; +export { Response_2 as Response } + export { } diff --git a/docs/generated/api.json b/docs/generated/api.json index 46e60be8..1234cde8 100644 --- a/docs/generated/api.json +++ b/docs/generated/api.json @@ -1091,8 +1091,8 @@ }, { "kind": "Reference", - "text": "express.Request", - "canonicalReference": "@types/express!~e.Request:interface" + "text": "Request", + "canonicalReference": "@google-cloud/functions-framework!Request:interface" }, { "kind": "Content", @@ -1100,8 +1100,8 @@ }, { "kind": "Reference", - "text": "express.Response", - "canonicalReference": "@types/express!~e.Response:interface" + "text": "Response", + "canonicalReference": "@google-cloud/functions-framework!Response:type" }, { "kind": "Content", @@ -1245,6 +1245,89 @@ } ], "extendsTokenRanges": [] + }, + { + "kind": "Interface", + "canonicalReference": "@google-cloud/functions-framework!Request_2:interface", + "docComment": "/**\n * @public\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "export interface Request extends " + }, + { + "kind": "Reference", + "text": "express.Request", + "canonicalReference": "@types/express!~e.Request:interface" + }, + { + "kind": "Content", + "text": " " + } + ], + "releaseTag": "Public", + "name": "Request_2", + "members": [ + { + "kind": "PropertySignature", + "canonicalReference": "@google-cloud/functions-framework!Request_2#rawBody:member", + "docComment": "/**\n * A buffer which provides access to the request's raw HTTP body.\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "rawBody?: " + }, + { + "kind": "Reference", + "text": "Buffer", + "canonicalReference": "!Buffer:class" + }, + { + "kind": "Content", + "text": ";" + } + ], + "isOptional": true, + "releaseTag": "Public", + "name": "rawBody", + "propertyTypeTokenRange": { + "startIndex": 1, + "endIndex": 2 + } + } + ], + "extendsTokenRanges": [ + { + "startIndex": 1, + "endIndex": 3 + } + ] + }, + { + "kind": "TypeAlias", + "canonicalReference": "@google-cloud/functions-framework!Response_2:type", + "docComment": "/**\n * @public\n */\n", + "excerptTokens": [ + { + "kind": "Content", + "text": "export declare type Response = " + }, + { + "kind": "Reference", + "text": "express.Response", + "canonicalReference": "@types/express!~e.Response:interface" + }, + { + "kind": "Content", + "text": ";" + } + ], + "releaseTag": "Public", + "name": "Response_2", + "typeTokenRange": { + "startIndex": 1, + "endIndex": 2 + } } ] } diff --git a/docs/generated/api.md b/docs/generated/api.md index 8db969a2..5f499f18 100644 --- a/docs/generated/api.md +++ b/docs/generated/api.md @@ -4,6 +4,8 @@ ```ts +/// + import * as express from 'express'; // @public @@ -75,7 +77,7 @@ export const http: (functionName: string, handler: HttpFunction) => void; // @public export interface HttpFunction { // (undocumented) - (req: express.Request, res: express.Response): any; + (req: Request_2, res: Response_2): any; } // @public @@ -91,6 +93,16 @@ export interface LegacyEvent { }; } +// @public (undocumented) +interface Request_2 extends express.Request { + rawBody?: Buffer; +} +export { Request_2 as Request } + +// @public (undocumented) +type Response_2 = express.Response; +export { Response_2 as Response } + // (No @packageDocumentation comment for this package) ``` diff --git a/src/functions.ts b/src/functions.ts index d29ec17c..f39cd50d 100644 --- a/src/functions.ts +++ b/src/functions.ts @@ -18,12 +18,27 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ import * as express from 'express'; +/** + * @public + */ +export interface Request extends express.Request { + /** + * A buffer which provides access to the request's raw HTTP body. + */ + rawBody?: Buffer; +} + +/** + * @public + */ +export type Response = express.Response; + /** * A HTTP function handler. * @public */ export interface HttpFunction { - (req: express.Request, res: express.Response): any; + (req: Request, res: Response): any; } /** * A legacy event function handler. diff --git a/src/invoker.ts b/src/invoker.ts index 8cde7775..e47ded44 100644 --- a/src/invoker.ts +++ b/src/invoker.ts @@ -24,17 +24,6 @@ import * as http from 'http'; import {FUNCTION_STATUS_HEADER_FIELD} from './types'; import {sendCrashResponse} from './logger'; -// We optionally annotate the express Request with a rawBody field. -// Express leaves the Express namespace open to allow merging of new fields. -declare global { - // eslint-disable-next-line @typescript-eslint/no-namespace - namespace Express { - export interface Request { - rawBody?: Buffer; - } - } -} - /** * Response object for the most recent request. * Used for sending errors to the user. diff --git a/src/server.ts b/src/server.ts index e137af64..67da78ef 100644 --- a/src/server.ts +++ b/src/server.ts @@ -16,7 +16,7 @@ import * as bodyParser from 'body-parser'; import * as express from 'express'; import * as http from 'http'; import * as onFinished from 'on-finished'; -import {HandlerFunction} from './functions'; +import {HandlerFunction, Request, Response} from './functions'; import {SignatureType} from './types'; import {setLatestRes} from './invoker'; import {legacyPubSubEventMiddleware} from './pubsub_middleware'; @@ -55,11 +55,7 @@ export function getServer( * @param res Express response object. * @param buf Buffer to be saved. */ - function rawBodySaver( - req: express.Request, - res: express.Response, - buf: Buffer - ) { + function rawBodySaver(req: Request, res: Response, buf: Buffer) { req.rawBody = buf; } diff --git a/test/integration/http.ts b/test/integration/http.ts index 68418f8f..65126a3c 100644 --- a/test/integration/http.ts +++ b/test/integration/http.ts @@ -13,9 +13,9 @@ // limitations under the License. import * as assert from 'assert'; -import * as express from 'express'; import {getServer} from '../../src/server'; import * as supertest from 'supertest'; +import {Request, Response} from '../../src/functions'; describe('HTTP Function', () => { const testData = [ @@ -64,16 +64,13 @@ describe('HTTP Function', () => { testData.forEach(test => { it(test.name, async () => { let callCount = 0; - const server = getServer( - (req: express.Request, res: express.Response) => { - ++callCount; - res.send({ - result: req.body.text, - query: req.query.param, - }); - }, - 'http' - ); + const server = getServer((req: Request, res: Response) => { + ++callCount; + res.send({ + result: req.body.text, + query: req.query.param, + }); + }, 'http'); const st = supertest(server); await (test.httpVerb === 'GET' ? st.get(test.path)