Skip to content

Commit c4c271a

Browse files
committed
Add request/response-body-data to track body streaming events
1 parent fe11c73 commit c4c271a

File tree

8 files changed

+520
-171
lines changed

8 files changed

+520
-171
lines changed

src/admin/mockttp-admin-model.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,10 @@ import { SubscribableEvent } from "../main";
3030

3131
const graphqlSubscriptionPairs = Object.entries({
3232
'requestInitiated': 'request-initiated',
33+
'requestBodyData': 'request-body-data',
3334
'requestReceived': 'request',
3435
'responseInitiated': 'response-initiated',
36+
'responseBodyData': 'response-body-data',
3537
'responseCompleted': 'response',
3638
'webSocketRequest': 'websocket-request',
3739
'webSocketAccepted': 'websocket-accepted',

src/admin/mockttp-schema.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,10 @@ export const MockttpSchema = gql`
1919
2020
extend type Subscription {
2121
requestInitiated: InitiatedRequest!
22+
requestBodyData: BodyData!
2223
requestReceived: Request!
2324
responseInitiated: InitiatedResponse!
25+
responseBodyData: BodyData!
2426
responseCompleted: Response!
2527
webSocketRequest: Request!
2628
webSocketAccepted: Response!
@@ -137,6 +139,13 @@ export const MockttpSchema = gql`
137139
eventData: Raw!
138140
}
139141
142+
type BodyData {
143+
id: String!
144+
content: Buffer!
145+
eventTimestamp: Float!
146+
isEnded: Boolean!
147+
}
148+
140149
type InitiatedRequest {
141150
id: ID!
142151
timingEvents: Json!

src/client/mockttp-admin-request-builder.ts

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -215,6 +215,14 @@ export class MockttpAdminRequestBuilder {
215215
tags
216216
}
217217
}`,
218+
'request-body-data': gql`subscription OnRequestBodyData {
219+
requestBodyData {
220+
id
221+
content
222+
eventTimestamp
223+
isEnded
224+
}
225+
}`,
218226
request: gql`subscription OnRequest {
219227
requestReceived {
220228
id
@@ -254,6 +262,14 @@ export class MockttpAdminRequestBuilder {
254262
tags
255263
}
256264
}`,
265+
'response-body-data': gql`subscription OnResponseBodyData {
266+
responseBodyData {
267+
id
268+
content
269+
eventTimestamp
270+
isEnded
271+
}
272+
}`,
257273
response: gql`subscription OnResponse {
258274
responseCompleted {
259275
id
@@ -528,7 +544,11 @@ export class MockttpAdminRequestBuilder {
528544
}
529545
} else if (event === 'websocket-message-received' || event === 'websocket-message-sent') {
530546
normalizeWebSocketMessage(data);
531-
} else if (event === 'raw-passthrough-data') {
547+
} else if (
548+
event === 'raw-passthrough-data' ||
549+
event === 'request-body-data' ||
550+
event === 'response-body-data'
551+
) {
532552
data.content = Buffer.from(data.content, 'base64');
533553
} else if (event === 'abort') {
534554
normalizeHttpMessage(data, event);

src/mockttp.ts

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,8 @@ import {
2323
RuleEvent,
2424
RawPassthroughEvent,
2525
RawPassthroughDataEvent,
26-
InitiatedResponse
26+
InitiatedResponse,
27+
BodyData
2728
} from "./types";
2829
import type { RequestRuleData } from "./rules/requests/request-rule";
2930
import type { WebSocketRuleData } from "./rules/websockets/websocket-rule";
@@ -355,6 +356,22 @@ export interface Mockttp {
355356
*/
356357
on(event: 'request-initiated', callback: (req: InitiatedRequest) => void): Promise<void>;
357358

359+
/**
360+
* Subscribe to hear about request body data live, streaming in progressive
361+
* chunks as it's received (listen for `request` if you just want to receive
362+
* the complete body once it's done).
363+
*
364+
* This is only useful in some niche use cases, such as logging all requests seen
365+
* by the server independently of the rules defined.
366+
*
367+
* The callback will be called asynchronously from request handling. This function
368+
* returns a promise, and the callback is not guaranteed to be registered until
369+
* the promise is resolved.
370+
*
371+
* @category Events
372+
*/
373+
on(event: 'request-body-data', callback: (req: BodyData) => void): Promise<void>;
374+
358375
/**
359376
* Subscribe to hear about request details once the request is fully received.
360377
*
@@ -384,6 +401,22 @@ export interface Mockttp {
384401
*/
385402
on(event: 'response-initiated', callback: (req: InitiatedResponse) => void): Promise<void>;
386403

404+
/**
405+
* Subscribe to hear about response body data live, streaming in progressive
406+
* chunks as it's received (listen for `response` if you just want to receive
407+
* the complete body once it's done).
408+
*
409+
* This is only useful in some niche use cases, such as logging all requests seen
410+
* by the server independently of the rules defined.
411+
*
412+
* The callback will be called asynchronously from request handling. This function
413+
* returns a promise, and the callback is not guaranteed to be registered until
414+
* the promise is resolved.
415+
*
416+
* @category Events
417+
*/
418+
on(event: 'response-body-data', callback: (req: BodyData) => void): Promise<void>;
419+
387420
/**
388421
* Subscribe to hear about response details when the response is completed.
389422
*
@@ -915,8 +948,10 @@ export interface MockttpOptions {
915948

916949
export type SubscribableEvent =
917950
| 'request-initiated'
951+
| 'request-body-data'
918952
| 'request'
919953
| 'response-initiated'
954+
| 'response-body-data'
920955
| 'response'
921956
| 'websocket-request'
922957
| 'websocket-accepted'

0 commit comments

Comments
 (0)