Skip to content

Commit 2e23e7c

Browse files
jbl428imdudu1
andcommitted
feat: implement body injecting
Co-authored-by: imdudu1 <[email protected]>
1 parent 204d01e commit 2e23e7c

File tree

3 files changed

+89
-1
lines changed

3 files changed

+89
-1
lines changed

lib/decorators/request-body.decorator.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { REQUEST_BODY_METADATA } from "./constants";
22
import { MetadataMap } from "../types/metadata-map";
33

4-
export type RequestBodyMetadata = Map<number, string | undefined>;
4+
export type RequestBodyMetadata = MetadataMap<number, string | undefined>;
55

66
export function RequestBody(key?: string): ParameterDecorator {
77
return (target, propertyKey, parameterIndex) => {

lib/node-fetch.injector.spec.ts

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import {
1010
PathVariable,
1111
PostExchange,
1212
PutExchange,
13+
RequestBody,
1314
RequestParam,
1415
} from "./decorators";
1516
import { StubDiscoveryService } from "./fixture/stub-discovery.service";
@@ -215,4 +216,54 @@ describe("NodeFetchInjector", () => {
215216
expect(httpClient.requestInfo).toHaveLength(1);
216217
expect(httpClient.requestInfo[0].method).toBe(method);
217218
});
219+
220+
test("should include body", async () => {
221+
// given
222+
@HttpInterface()
223+
class SampleClient {
224+
@PostExchange("https://example.com/api")
225+
async request(@RequestBody("name") name: string): Promise<string> {
226+
return "request";
227+
}
228+
}
229+
const instance = discoveryService.addProvider(SampleClient);
230+
httpClient.addResponse({ status: "ok" });
231+
nodeFetchInjector.onModuleInit();
232+
233+
// when
234+
await instance.request("userName");
235+
236+
// then
237+
expect(httpClient.requestInfo).toHaveLength(1);
238+
expect(await httpClient.requestInfo[0].text()).toBe('{"name":"userName"}');
239+
expect(httpClient.requestInfo[0].headers.get("Content-Type")).toBe(
240+
"application/json"
241+
);
242+
});
243+
244+
test("should include body provided by json", async () => {
245+
// given
246+
@HttpInterface()
247+
class SampleClient {
248+
@PostExchange("https://example.com/api")
249+
async request(
250+
@RequestBody() body: Record<string, unknown>
251+
): Promise<string> {
252+
return "request";
253+
}
254+
}
255+
const instance = discoveryService.addProvider(SampleClient);
256+
httpClient.addResponse({ status: "ok" });
257+
nodeFetchInjector.onModuleInit();
258+
259+
// when
260+
await instance.request({ name: "userName" });
261+
262+
// then
263+
expect(httpClient.requestInfo).toHaveLength(1);
264+
expect(await httpClient.requestInfo[0].text()).toBe('{"name":"userName"}');
265+
expect(httpClient.requestInfo[0].headers.get("Content-Type")).toBe(
266+
"application/json"
267+
);
268+
});
218269
});

lib/node-fetch.injector.ts

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,13 @@ import {
77
type HttpExchangeMetadata,
88
PATH_VARIABLE_METADATA,
99
type PathVariableMetadata,
10+
REQUEST_BODY_METADATA,
1011
REQUEST_PARAM_METADATA,
12+
type RequestBodyMetadata,
1113
type RequestParamMetadata,
1214
} from "./decorators";
1315
import { HttpClient } from "./types/http-client.interface";
16+
import { TupleArrayBuilder } from "./utils/tuple-array-builder";
1417
import { URLBuilder } from "./utils/url-builder";
1518

1619
@Injectable()
@@ -53,8 +56,34 @@ export class NodeFetchInjector implements OnModuleInit {
5356
const requestParamMetadata = getMetadata<RequestParamMetadata>(
5457
REQUEST_PARAM_METADATA
5558
);
59+
const requestBodyMetadata = getMetadata<RequestBodyMetadata>(
60+
REQUEST_BODY_METADATA
61+
);
5662

5763
wrapper.instance[methodName] = async (...args: any[]) => {
64+
const payload = requestBodyMetadata
65+
?.toArray()
66+
.reduce(
67+
(
68+
acc: Record<string, unknown>,
69+
[index, value]: [number, any]
70+
) => {
71+
if (typeof value !== "undefined") {
72+
acc[value] = args[index];
73+
return acc;
74+
}
75+
76+
TupleArrayBuilder.of<string, unknown>(args[index]).forEach(
77+
([k, v]) => {
78+
acc[k] = v;
79+
}
80+
);
81+
82+
return acc;
83+
},
84+
{}
85+
);
86+
5887
const urlBuilder = new URLBuilder(
5988
baseUrl,
6089
httpExchangeMetadata.url,
@@ -69,6 +98,14 @@ export class NodeFetchInjector implements OnModuleInit {
6998
.request(
7099
new Request(urlBuilder.build(), {
71100
method: httpExchangeMetadata.method,
101+
headers:
102+
typeof payload !== "undefined"
103+
? { "Content-Type": "application/json" }
104+
: undefined,
105+
body:
106+
typeof payload !== "undefined"
107+
? JSON.stringify(payload)
108+
: undefined,
72109
})
73110
)
74111
.then(async (response) => await response.json());

0 commit comments

Comments
 (0)