Skip to content

Commit 93b1197

Browse files
salmankhan-prssalmankhangeekyshubham1172
authored
feat(invocation): Allow sending and receiving headers during HTTP service invocation (#408)
* added the doc comment to invokeroption Signed-off-by: pathan salman khan <[email protected]> * Update src/types/InvokerOptions.type.ts Co-authored-by: Shubham Sharma <[email protected]> Signed-off-by: PATHAN SALMAN KHAN <[email protected]> * Update src/types/InvokerOptions.type.ts Co-authored-by: Shubham Sharma <[email protected]> Signed-off-by: PATHAN SALMAN KHAN <[email protected]> * fixed prettier Signed-off-by: pathan salman khan <[email protected]> * fixed the requested changes Signed-off-by: pathan salman khan <[email protected]> * Fix e2e test and nit Signed-off-by: Shubham Sharma <[email protected]> * Add invoker header options and e2e test Signed-off-by: Shubham Sharma <[email protected]> * Prettify all Signed-off-by: Shubham Sharma <[email protected]> * Export types for callback Signed-off-by: Shubham Sharma <[email protected]> * Add docs Signed-off-by: Shubham Sharma <[email protected]> * Prettify all Signed-off-by: Shubham Sharma <[email protected]> * Update type Signed-off-by: Shubham Sharma <[email protected]> * Prettify all Signed-off-by: Shubham Sharma <[email protected]> * Update example Signed-off-by: Shubham Sharma <[email protected]> * Prettify all Signed-off-by: Shubham Sharma <[email protected]> * Fix lint Signed-off-by: Shubham Sharma <[email protected]> Signed-off-by: pathan salman khan <[email protected]> Signed-off-by: PATHAN SALMAN KHAN <[email protected]> Signed-off-by: Shubham Sharma <[email protected]> Co-authored-by: pathan salman khan <[email protected]> Co-authored-by: Shubham Sharma <[email protected]>
1 parent 911e250 commit 93b1197

File tree

14 files changed

+143
-48
lines changed

14 files changed

+143
-48
lines changed

daprdocs/content/en/js-sdk-docs/js-client/_index.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,15 @@ async function start() {
128128
// POST Request
129129
const response = await client.invoker.invoke(serviceAppId, serviceMethod, HttpMethod.POST, { hello: "world" });
130130

131+
// POST Request with headers
132+
const response = await client.invoker.invoke(
133+
serviceAppId,
134+
serviceMethod,
135+
HttpMethod.POST,
136+
{ hello: "world" },
137+
{ headers: { "X-User-ID": "123" } },
138+
);
139+
131140
// GET Request
132141
const response = await client.invoker.invoke(serviceAppId, serviceMethod, HttpMethod.GET);
133142
}

daprdocs/content/en/js-sdk-docs/js-server/_index.md

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@ The JavaScript Server SDK allows you to interface with all of the [Dapr building
9898
#### Listen to an Invocation
9999

100100
```typescript
101-
import { DaprServer } from "@dapr/dapr";
101+
import { DaprServer, DaprInvokerCallbackContent } from "@dapr/dapr";
102102

103103
const daprHost = "127.0.0.1"; // Dapr Sidecar Host
104104
const daprPort = "3500"; // Dapr Sidecar Port of this Example Server
@@ -108,7 +108,14 @@ const serverPort = "50051"; // App Port of this Example Server "
108108
async function start() {
109109
const server = new DaprServer(serverHost, serverPort, daprHost, daprPort);
110110

111-
await server.invoker.listen("hello-world", mock, { method: HttpMethod.GET });
111+
const callbackFunction = (data: DaprInvokerCallbackContent) => {
112+
console.log("Received body: ", data.body);
113+
console.log("Received metadata: ", data.metadata);
114+
console.log("Received query: ", data.query);
115+
console.log("Received headers: ", data.headers); // only available in HTTP
116+
};
117+
118+
await server.invoker.listen("hello-world", callbackFunction, { method: HttpMethod.GET });
112119

113120
// You can now invoke the service with your app id and method "hello-world"
114121

examples/invocation/src/index.ts

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ See the License for the specific language governing permissions and
1111
limitations under the License.
1212
*/
1313

14-
import { DaprServer, DaprClient, HttpMethod } from "@dapr/dapr";
14+
import { DaprServer, DaprClient, HttpMethod, DaprInvokerCallbackContent } from "@dapr/dapr";
1515

1616
// Common settings
1717
const daprAppId = "example-invocation";
@@ -20,20 +20,19 @@ const daprHost = "127.0.0.1";
2020
const serverPort = "50051"; // App Port of this Example Server
2121

2222
async function start() {
23-
// Note that the DAPR_HTTP_PORT and DAPR_GRPC_PORT environment variables are set by DAPR itself. https://docs.dapr.io/reference/environment/
24-
const server = new DaprServer(serverHost, serverPort, daprHost, process.env.DAPR_HTTP_PORT);
25-
26-
const client = new DaprClient(daprHost, process.env.DAPR_HTTP_PORT);
23+
const server = new DaprServer(serverHost, serverPort, daprHost);
24+
const client = new DaprClient(daprHost);
2725

2826
// Note that invoker listeners can be set up after start() has been called
2927
await server.start();
3028

3129
console.log("Setting up invocation endpoints");
3230
await server.invoker.listen(
3331
"hello-world",
34-
async (data: Record<string, any>) => {
32+
async (data: DaprInvokerCallbackContent) => {
3533
// Data is automatically parsed when received
36-
console.log(`Received: ${JSON.stringify(data.body)} on POST hello-world`);
34+
console.log(`Received: ${JSON.stringify(data.body)} as body on POST hello-world`);
35+
console.log(`Received: ${JSON.stringify(data.headers)} as headers on POST hello-world`);
3736
return { hello: "world received from POST" };
3837
},
3938
{ method: HttpMethod.POST },
@@ -48,10 +47,17 @@ async function start() {
4847
{ method: HttpMethod.GET },
4948
);
5049

50+
// Wait for 500ms to allow the server to start
51+
await new Promise((resolve) => setTimeout(resolve, 500));
52+
5153
console.log("Invoking endpoints");
52-
const r = await client.invoker.invoke(daprAppId, "hello-world", HttpMethod.POST, {
53-
hello: "world",
54-
});
54+
const r = await client.invoker.invoke(
55+
daprAppId,
56+
"hello-world",
57+
HttpMethod.POST,
58+
{ hello: "world" },
59+
{ headers: { "X-Application-Type": "examples/invocation" } },
60+
);
5561
console.log(`Response to POST request: ${JSON.stringify(r)}`);
5662
const r2 = await client.invoker.invoke(daprAppId, "hello-world", HttpMethod.GET);
5763
console.log(`Response to GET request: ${JSON.stringify(r2)}`);

src/implementation/Client/GRPCClient/invoker.ts

Lines changed: 3 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import { InvokeServiceRequest } from "../../../proto/dapr/proto/runtime/v1/dapr_
2020
import * as HttpVerbUtil from "../../../utils/HttpVerb.util";
2121
import IClientInvoker from "../../../interfaces/Client/IClientInvoker";
2222
import * as SerializerUtil from "../../../utils/Serializer.util";
23+
import { InvokerOptions } from "../../../types/InvokerOptions.type";
2324

2425
// https://docs.dapr.io/reference/api/service_invocation_api/
2526
export default class GRPCClientInvoker implements IClientInvoker {
@@ -30,28 +31,14 @@ export default class GRPCClientInvoker implements IClientInvoker {
3031
}
3132

3233
// @todo: should return a specific typed Promise<TypeInvokerInvokeResponse> instead of Promise<nothing>
34+
3335
async invoke(
3436
appId: string,
3537
methodName: string,
3638
method: HttpMethod = HttpMethod.GET,
3739
data: object = {},
40+
_options: InvokerOptions = {},
3841
): Promise<object> {
39-
const fetchOptions = {
40-
method,
41-
};
42-
43-
if (method !== HttpMethod.GET) {
44-
// @ts-ignore
45-
fetchOptions.headers = {
46-
"Content-Type": "application/json",
47-
};
48-
}
49-
50-
if (method !== HttpMethod.GET) {
51-
// @ts-ignore
52-
fetchOptions.body = JSON.stringify(data);
53-
}
54-
5542
// InvokeServiceRequest represents the request message for Service invocation.
5643
const msgInvokeService = new InvokeServiceRequest();
5744
msgInvokeService.setId(appId);

src/implementation/Client/HTTPClient/invoker.ts

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ limitations under the License.
1414
import HTTPClient from "./HTTPClient";
1515
import { HttpMethod } from "../../../enum/HttpMethod.enum";
1616
import IClientInvoker from "../../../interfaces/Client/IClientInvoker";
17+
import { InvokerOptions } from "../../../types/InvokerOptions.type";
1718

1819
// https://docs.dapr.io/reference/api/service_invocation_api/
1920
export default class HTTPClientInvoker implements IClientInvoker {
@@ -23,20 +24,27 @@ export default class HTTPClientInvoker implements IClientInvoker {
2324
this.client = client;
2425
}
2526

26-
async invoke(appId: string, methodName: string, method: HttpMethod = HttpMethod.GET, data?: object): Promise<object> {
27+
async invoke(
28+
appId: string,
29+
methodName: string,
30+
method: HttpMethod = HttpMethod.GET,
31+
data?: object,
32+
options: InvokerOptions = {},
33+
): Promise<object> {
34+
const headers = options.headers ?? {};
35+
2736
const fetchOptions = {
2837
method,
38+
headers,
2939
};
3040

3141
if (method !== HttpMethod.GET) {
32-
// @ts-ignore
33-
fetchOptions.headers = {
34-
"Content-Type": "application/json",
35-
};
42+
//@ts-ignore
43+
fetchOptions.headers["Content-Type"] = "application/json";
3644
}
3745

3846
if (method !== HttpMethod.GET && data !== undefined) {
39-
// @ts-ignore
47+
//@ts-ignore
4048
fetchOptions.body = JSON.stringify(data);
4149
}
4250

src/implementation/Server/GRPCServer/GRPCServerImpl.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,6 @@ import {
2828
TopicRule,
2929
TopicSubscription,
3030
} from "../../../proto/dapr/proto/runtime/v1/appcallback_pb";
31-
import { TypeDaprInvokerCallback } from "../../../types/DaprInvokerCallback.type";
3231
import * as HttpVerbUtil from "../../../utils/HttpVerb.util";
3332
import { TypeDaprBindingCallback } from "../../../types/DaprBindingCallback.type";
3433
import { TypeDaprPubSubCallback } from "../../../types/DaprPubSubCallback.type";
@@ -39,6 +38,7 @@ import { IServerType } from "./GRPCServer";
3938
import { PubSubSubscriptionsType } from "../../../types/pubsub/PubSubSubscriptions.type";
4039
import { DaprPubSubType } from "../../../types/pubsub/DaprPubSub.type";
4140
import { PubSubSubscriptionTopicRoutesType } from "../../../types/pubsub/PubSubSubscriptionTopicRoutes.type";
41+
import { DaprInvokerCallbackFunction } from "../../../types/DaprInvokerCallback.type";
4242

4343
// https://github.com/badsyntax/grpc-js-typescript/issues/1#issuecomment-705419742
4444
// @ts-ignore
@@ -48,7 +48,7 @@ export default class GRPCServerImpl implements IAppCallbackServer {
4848
private readonly logger: Logger;
4949
private readonly server: IServerType;
5050

51-
handlersInvoke: { [key: string]: TypeDaprInvokerCallback };
51+
handlersInvoke: { [key: string]: DaprInvokerCallbackFunction };
5252
handlersBindings: { [key: string]: TypeDaprBindingCallback };
5353
pubSubSubscriptions: PubSubSubscriptionsType;
5454

@@ -73,7 +73,7 @@ export default class GRPCServerImpl implements IAppCallbackServer {
7373
return `${httpMethod.toLowerCase()}|${methodName.toLowerCase()}`;
7474
}
7575

76-
registerOnInvokeHandler(httpMethod: string, methodName: string, cb: TypeDaprInvokerCallback): void {
76+
registerOnInvokeHandler(httpMethod: string, methodName: string, cb: DaprInvokerCallbackFunction): void {
7777
const handlerKey = this.createOnInvokeHandlerKey(httpMethod, methodName);
7878
this.handlersInvoke[handlerKey] = cb;
7979
}
@@ -313,7 +313,7 @@ export default class GRPCServerImpl implements IAppCallbackServer {
313313
return `${pubsubName.toLowerCase()}--${topic.toLowerCase()}--${routeParsed}`;
314314
}
315315

316-
registerInputBindingHandler(bindingName: string, cb: TypeDaprInvokerCallback): void {
316+
registerInputBindingHandler(bindingName: string, cb: DaprInvokerCallbackFunction): void {
317317
const handlerKey = this.createInputBindingHandlerKey(bindingName);
318318
this.handlersBindings[handlerKey] = cb;
319319
}

src/implementation/Server/GRPCServer/invoker.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,11 @@ limitations under the License.
1212
*/
1313

1414
import GRPCServer from "./GRPCServer";
15-
import { TypeDaprInvokerCallback } from "../../../types/DaprInvokerCallback.type";
1615
import { InvokerListenOptionsType } from "../../../types/InvokerListenOptions.type";
1716
import { HttpMethod } from "../../../enum/HttpMethod.enum";
1817
import IServerInvoker from "../../../interfaces/Server/IServerInvoker";
1918
import { Logger } from "../../../logger/Logger";
19+
import { DaprInvokerCallbackFunction } from "../../../types/DaprInvokerCallback.type";
2020

2121
// https://docs.dapr.io/reference/api/service_invocation_api/
2222
export default class DaprInvoker implements IServerInvoker {
@@ -28,7 +28,11 @@ export default class DaprInvoker implements IServerInvoker {
2828
this.logger = new Logger("GRPCServer", "Invoker", server.client.options.logger);
2929
}
3030

31-
async listen(methodName: string, cb: TypeDaprInvokerCallback, options: InvokerListenOptionsType = {}): Promise<any> {
31+
async listen(
32+
methodName: string,
33+
cb: DaprInvokerCallbackFunction,
34+
options: InvokerListenOptionsType = {},
35+
): Promise<any> {
3236
const httpMethod: HttpMethod = (options?.method?.toLowerCase() as HttpMethod) || HttpMethod.GET;
3337
this.logger.info(`Registering onInvoke Handler ${httpMethod} /${methodName}`);
3438
this.server.getServerImpl().registerOnInvokeHandler(httpMethod, methodName, cb);

src/implementation/Server/HTTPServer/invoker.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ See the License for the specific language governing permissions and
1111
limitations under the License.
1212
*/
1313

14-
import { TypeDaprInvokerCallback } from "../../../types/DaprInvokerCallback.type";
14+
import { DaprInvokerCallbackFunction } from "../../../types/DaprInvokerCallback.type";
1515
import { InvokerListenOptionsType } from "../../../types/InvokerListenOptions.type";
1616
import { HttpMethod } from "../../../enum/HttpMethod.enum";
1717
import HTTPServer from "./HTTPServer";
@@ -28,18 +28,18 @@ export default class HTTPServerInvoker implements IServerInvoker {
2828
this.logger = new Logger("HTTPServer", "Invoker", server.client.options.logger);
2929
}
3030

31-
async listen(methodName: string, cb: TypeDaprInvokerCallback, options: InvokerListenOptionsType = {}) {
31+
async listen(methodName: string, cb: DaprInvokerCallbackFunction, options: InvokerListenOptionsType = {}) {
3232
const serverMethod: HttpMethod = (options?.method?.toLowerCase() as HttpMethod) || HttpMethod.GET;
3333

3434
const server = await this.server.getServer();
35-
// @TODO should pass rest of headers to callback
3635
server[serverMethod](`/${methodName}`, async (req, res) => {
3736
const invokeResponse = await cb({
3837
body: JSON.stringify(req.body),
3938
query: req.originalUrl,
4039
metadata: {
4140
contentType: req.headers["content-type"],
4241
},
42+
headers: req.headers,
4343
});
4444

4545
// Make sure we close the request after the callback

src/index.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,8 @@ import { ConsoleLoggerService } from "./logger/ConsoleLoggerService";
2626
import { LogLevel } from "./types/logger/LogLevel";
2727
import GRPCClient from "./implementation/Client/GRPCClient/GRPCClient";
2828
import HTTPClient from "./implementation/Client/HTTPClient/HTTPClient";
29-
29+
import { InvokerOptions } from "./types/InvokerOptions.type";
30+
import { DaprInvokerCallbackContent, DaprInvokerCallbackFunction } from "./types/DaprInvokerCallback.type";
3031
export {
3132
DaprClient,
3233
DaprServer,
@@ -43,4 +44,7 @@ export {
4344
LoggerOptions,
4445
LoggerService,
4546
ConsoleLoggerService,
47+
InvokerOptions,
48+
DaprInvokerCallbackFunction as TypeDaprInvokerCallback,
49+
DaprInvokerCallbackContent,
4650
};

src/interfaces/Client/IClientInvoker.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,14 @@ limitations under the License.
1212
*/
1313

1414
import { HttpMethod } from "../../enum/HttpMethod.enum";
15+
import { InvokerOptions } from "../../types/InvokerOptions.type";
1516

1617
export default interface IClientInvoker {
17-
invoke(appId: string, methodName: string, method: HttpMethod, data?: object): Promise<object>;
18+
invoke(
19+
appId: string,
20+
methodName: string,
21+
method: HttpMethod,
22+
data?: object,
23+
options?: InvokerOptions,
24+
): Promise<object>;
1825
}

0 commit comments

Comments
 (0)