Skip to content

Commit

Permalink
fix!: Add type annotation for Request.rawBody
Browse files Browse the repository at this point in the history
We are store the raw HTTP body on a `rawBody` field of the HTTP Request object. This commit adds a type annotation for it.
  • Loading branch information
Gutza committed Oct 27, 2021
1 parent 8110d3a commit 60edd7e
Show file tree
Hide file tree
Showing 7 changed files with 146 additions and 35 deletions.
21 changes: 20 additions & 1 deletion docs/generated/api.d.ts
@@ -1,3 +1,5 @@
/// <reference types="node" />

import * as express from 'express';

/**
Expand Down Expand Up @@ -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;
}

/**
Expand All @@ -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 { }
91 changes: 87 additions & 4 deletions docs/generated/api.json
Expand Up @@ -1091,17 +1091,17 @@
},
{
"kind": "Reference",
"text": "express.Request",
"canonicalReference": "@types/express!~e.Request:interface"
"text": "Request",
"canonicalReference": "@google-cloud/functions-framework!Request:interface"
},
{
"kind": "Content",
"text": ", res: "
},
{
"kind": "Reference",
"text": "express.Response",
"canonicalReference": "@types/express!~e.Response:interface"
"text": "Response",
"canonicalReference": "@google-cloud/functions-framework!Response:type"
},
{
"kind": "Content",
Expand Down Expand Up @@ -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
}
}
]
}
Expand Down
14 changes: 13 additions & 1 deletion docs/generated/api.md
Expand Up @@ -4,6 +4,8 @@
```ts

/// <reference types="node" />

import * as express from 'express';

// @public
Expand Down Expand Up @@ -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
Expand All @@ -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)

```
17 changes: 16 additions & 1 deletion src/functions.ts
Expand Up @@ -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.
Expand Down
11 changes: 0 additions & 11 deletions src/invoker.ts
Expand Up @@ -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.
Expand Down
8 changes: 2 additions & 6 deletions src/server.ts
Expand Up @@ -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';
Expand Down Expand Up @@ -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;
}

Expand Down
19 changes: 8 additions & 11 deletions test/integration/http.ts
Expand Up @@ -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 = [
Expand Down Expand Up @@ -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)
Expand Down

0 comments on commit 60edd7e

Please sign in to comment.