Skip to content

Commit 60edd7e

Browse files
authored
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.
1 parent 8110d3a commit 60edd7e

File tree

7 files changed

+146
-35
lines changed

7 files changed

+146
-35
lines changed

docs/generated/api.d.ts

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
/// <reference types="node" />
2+
13
import * as express from 'express';
24

35
/**
@@ -149,7 +151,7 @@ export declare const http: (functionName: string, handler: HttpFunction) => void
149151
* @public
150152
*/
151153
export declare interface HttpFunction {
152-
(req: express.Request, res: express.Response): any;
154+
(req: Request_2, res: Response_2): any;
153155
}
154156

155157
/**
@@ -169,4 +171,21 @@ export declare interface LegacyEvent {
169171
context: CloudFunctionsContext;
170172
}
171173

174+
/**
175+
* @public
176+
*/
177+
declare interface Request_2 extends express.Request {
178+
/**
179+
* A buffer which provides access to the request's raw HTTP body.
180+
*/
181+
rawBody?: Buffer;
182+
}
183+
export { Request_2 as Request }
184+
185+
/**
186+
* @public
187+
*/
188+
declare type Response_2 = express.Response;
189+
export { Response_2 as Response }
190+
172191
export { }

docs/generated/api.json

Lines changed: 87 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1091,17 +1091,17 @@
10911091
},
10921092
{
10931093
"kind": "Reference",
1094-
"text": "express.Request",
1095-
"canonicalReference": "@types/express!~e.Request:interface"
1094+
"text": "Request",
1095+
"canonicalReference": "@google-cloud/functions-framework!Request:interface"
10961096
},
10971097
{
10981098
"kind": "Content",
10991099
"text": ", res: "
11001100
},
11011101
{
11021102
"kind": "Reference",
1103-
"text": "express.Response",
1104-
"canonicalReference": "@types/express!~e.Response:interface"
1103+
"text": "Response",
1104+
"canonicalReference": "@google-cloud/functions-framework!Response:type"
11051105
},
11061106
{
11071107
"kind": "Content",
@@ -1245,6 +1245,89 @@
12451245
}
12461246
],
12471247
"extendsTokenRanges": []
1248+
},
1249+
{
1250+
"kind": "Interface",
1251+
"canonicalReference": "@google-cloud/functions-framework!Request_2:interface",
1252+
"docComment": "/**\n * @public\n */\n",
1253+
"excerptTokens": [
1254+
{
1255+
"kind": "Content",
1256+
"text": "export interface Request extends "
1257+
},
1258+
{
1259+
"kind": "Reference",
1260+
"text": "express.Request",
1261+
"canonicalReference": "@types/express!~e.Request:interface"
1262+
},
1263+
{
1264+
"kind": "Content",
1265+
"text": " "
1266+
}
1267+
],
1268+
"releaseTag": "Public",
1269+
"name": "Request_2",
1270+
"members": [
1271+
{
1272+
"kind": "PropertySignature",
1273+
"canonicalReference": "@google-cloud/functions-framework!Request_2#rawBody:member",
1274+
"docComment": "/**\n * A buffer which provides access to the request's raw HTTP body.\n */\n",
1275+
"excerptTokens": [
1276+
{
1277+
"kind": "Content",
1278+
"text": "rawBody?: "
1279+
},
1280+
{
1281+
"kind": "Reference",
1282+
"text": "Buffer",
1283+
"canonicalReference": "!Buffer:class"
1284+
},
1285+
{
1286+
"kind": "Content",
1287+
"text": ";"
1288+
}
1289+
],
1290+
"isOptional": true,
1291+
"releaseTag": "Public",
1292+
"name": "rawBody",
1293+
"propertyTypeTokenRange": {
1294+
"startIndex": 1,
1295+
"endIndex": 2
1296+
}
1297+
}
1298+
],
1299+
"extendsTokenRanges": [
1300+
{
1301+
"startIndex": 1,
1302+
"endIndex": 3
1303+
}
1304+
]
1305+
},
1306+
{
1307+
"kind": "TypeAlias",
1308+
"canonicalReference": "@google-cloud/functions-framework!Response_2:type",
1309+
"docComment": "/**\n * @public\n */\n",
1310+
"excerptTokens": [
1311+
{
1312+
"kind": "Content",
1313+
"text": "export declare type Response = "
1314+
},
1315+
{
1316+
"kind": "Reference",
1317+
"text": "express.Response",
1318+
"canonicalReference": "@types/express!~e.Response:interface"
1319+
},
1320+
{
1321+
"kind": "Content",
1322+
"text": ";"
1323+
}
1324+
],
1325+
"releaseTag": "Public",
1326+
"name": "Response_2",
1327+
"typeTokenRange": {
1328+
"startIndex": 1,
1329+
"endIndex": 2
1330+
}
12481331
}
12491332
]
12501333
}

docs/generated/api.md

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44
55
```ts
66

7+
/// <reference types="node" />
8+
79
import * as express from 'express';
810

911
// @public
@@ -75,7 +77,7 @@ export const http: (functionName: string, handler: HttpFunction) => void;
7577
// @public
7678
export interface HttpFunction {
7779
// (undocumented)
78-
(req: express.Request, res: express.Response): any;
80+
(req: Request_2, res: Response_2): any;
7981
}
8082

8183
// @public
@@ -91,6 +93,16 @@ export interface LegacyEvent {
9193
};
9294
}
9395

96+
// @public (undocumented)
97+
interface Request_2 extends express.Request {
98+
rawBody?: Buffer;
99+
}
100+
export { Request_2 as Request }
101+
102+
// @public (undocumented)
103+
type Response_2 = express.Response;
104+
export { Response_2 as Response }
105+
94106
// (No @packageDocumentation comment for this package)
95107

96108
```

src/functions.ts

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,27 @@
1818
/* eslint-disable @typescript-eslint/no-explicit-any */
1919
import * as express from 'express';
2020

21+
/**
22+
* @public
23+
*/
24+
export interface Request extends express.Request {
25+
/**
26+
* A buffer which provides access to the request's raw HTTP body.
27+
*/
28+
rawBody?: Buffer;
29+
}
30+
31+
/**
32+
* @public
33+
*/
34+
export type Response = express.Response;
35+
2136
/**
2237
* A HTTP function handler.
2338
* @public
2439
*/
2540
export interface HttpFunction {
26-
(req: express.Request, res: express.Response): any;
41+
(req: Request, res: Response): any;
2742
}
2843
/**
2944
* A legacy event function handler.

src/invoker.ts

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -24,17 +24,6 @@ import * as http from 'http';
2424
import {FUNCTION_STATUS_HEADER_FIELD} from './types';
2525
import {sendCrashResponse} from './logger';
2626

27-
// We optionally annotate the express Request with a rawBody field.
28-
// Express leaves the Express namespace open to allow merging of new fields.
29-
declare global {
30-
// eslint-disable-next-line @typescript-eslint/no-namespace
31-
namespace Express {
32-
export interface Request {
33-
rawBody?: Buffer;
34-
}
35-
}
36-
}
37-
3827
/**
3928
* Response object for the most recent request.
4029
* Used for sending errors to the user.

src/server.ts

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ import * as bodyParser from 'body-parser';
1616
import * as express from 'express';
1717
import * as http from 'http';
1818
import * as onFinished from 'on-finished';
19-
import {HandlerFunction} from './functions';
19+
import {HandlerFunction, Request, Response} from './functions';
2020
import {SignatureType} from './types';
2121
import {setLatestRes} from './invoker';
2222
import {legacyPubSubEventMiddleware} from './pubsub_middleware';
@@ -55,11 +55,7 @@ export function getServer(
5555
* @param res Express response object.
5656
* @param buf Buffer to be saved.
5757
*/
58-
function rawBodySaver(
59-
req: express.Request,
60-
res: express.Response,
61-
buf: Buffer
62-
) {
58+
function rawBodySaver(req: Request, res: Response, buf: Buffer) {
6359
req.rawBody = buf;
6460
}
6561

test/integration/http.ts

Lines changed: 8 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,9 @@
1313
// limitations under the License.
1414

1515
import * as assert from 'assert';
16-
import * as express from 'express';
1716
import {getServer} from '../../src/server';
1817
import * as supertest from 'supertest';
18+
import {Request, Response} from '../../src/functions';
1919

2020
describe('HTTP Function', () => {
2121
const testData = [
@@ -64,16 +64,13 @@ describe('HTTP Function', () => {
6464
testData.forEach(test => {
6565
it(test.name, async () => {
6666
let callCount = 0;
67-
const server = getServer(
68-
(req: express.Request, res: express.Response) => {
69-
++callCount;
70-
res.send({
71-
result: req.body.text,
72-
query: req.query.param,
73-
});
74-
},
75-
'http'
76-
);
67+
const server = getServer((req: Request, res: Response) => {
68+
++callCount;
69+
res.send({
70+
result: req.body.text,
71+
query: req.query.param,
72+
});
73+
}, 'http');
7774
const st = supertest(server);
7875
await (test.httpVerb === 'GET'
7976
? st.get(test.path)

0 commit comments

Comments
 (0)