Skip to content

Commit 34cd255

Browse files
MaryGaoxirzec
andauthored
Support to customize the client request id header when creating pipelines (Azure#26424)
### Packages impacted by this PR @azure/core-rest-pipeline ### Issues associated with this PR Azure/autorest.typescript#1906 (comment) ### Describe the problem that is addressed by this PR Batch service has the requirement to custom their request id header to `client-request-id` ([tsp here](https://github.com/Azure/azure-rest-api-specs/blob/b37ad7f957f0c6f9dd149546e46399308f83b366/specification/batch/Batch/routes.tsp#L2719-L2727)). Currently the header name is fixed as default value `x-ms-client-request-id` in setClientRequestIdPolicy. So I think we could open an option in PipelineOptions to allow customizing this header. ### What are the possible designs available to address the problem? If there are more than one possible design, why was the one in this PR chosen? Another option to support this is to add a customized policy from SDK side, to achieve that we could: - remove the default setClientRequestIdPolicy - re-add a new setClientRequestIdPolicy policy and set the header with customized name Compared to the latter one I think the current implementation would be more generic and elegant and can easily apply to more cases in future. But I'm also open for better options. ### References - Azure/azure-sdk-for-python#30771 --------- Co-authored-by: Jeff Fisher <[email protected]>
1 parent 3e92d4e commit 34cd255

File tree

5 files changed

+110
-1
lines changed

5 files changed

+110
-1
lines changed

sdk/core/core-rest-pipeline/CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44

55
### Features Added
66

7+
- Add CommonTelemetryOptions in PipelineOptions to allow customizing the client request id header name [PR #26424](https://github.com/Azure/azure-sdk-for-js/pull/26424)
8+
79
### Breaking Changes
810

911
### Bugs Fixed

sdk/core/core-rest-pipeline/review/core-rest-pipeline.api.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -208,6 +208,7 @@ export interface PipelineOptions {
208208
proxyOptions?: ProxySettings;
209209
redirectOptions?: RedirectPolicyOptions;
210210
retryOptions?: PipelineRetryOptions;
211+
telemetryOptions?: TelemetryOptions;
211212
tlsOptions?: TlsSettings;
212213
userAgentOptions?: UserAgentPolicyOptions;
213214
}
@@ -400,6 +401,11 @@ export interface SystemErrorRetryPolicyOptions {
400401
retryDelayInMs?: number;
401402
}
402403

404+
// @public
405+
export interface TelemetryOptions {
406+
clientRequestIdHeaderName?: string;
407+
}
408+
403409
// @public
404410
export function throttlingRetryPolicy(options?: ThrottlingRetryPolicyOptions): PipelinePolicy;
405411

sdk/core/core-rest-pipeline/src/createPipelineFromOptions.ts

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,21 @@ export interface PipelineOptions {
4444
* Options for adding user agent details to outgoing requests.
4545
*/
4646
userAgentOptions?: UserAgentPolicyOptions;
47+
48+
/**
49+
* Options for setting common telemetry and tracing info to outgoing requests.
50+
*/
51+
telemetryOptions?: TelemetryOptions;
52+
}
53+
54+
/**
55+
* Defines options that are used to configure common telemetry and tracing info
56+
*/
57+
export interface TelemetryOptions {
58+
/**
59+
* The name of the header to pass the request ID to.
60+
*/
61+
clientRequestIdHeaderName?: string;
4762
}
4863

4964
/**
@@ -74,7 +89,7 @@ export function createPipelineFromOptions(options: InternalPipelineOptions): Pip
7489

7590
pipeline.addPolicy(formDataPolicy());
7691
pipeline.addPolicy(userAgentPolicy(options.userAgentOptions));
77-
pipeline.addPolicy(setClientRequestIdPolicy());
92+
pipeline.addPolicy(setClientRequestIdPolicy(options.telemetryOptions?.clientRequestIdHeaderName));
7893
pipeline.addPolicy(defaultRetryPolicy(options.retryOptions), { phase: "Retry" });
7994
pipeline.addPolicy(tracingPolicy(options.userAgentOptions), { afterPhase: "Retry" });
8095
if (isNode) {

sdk/core/core-rest-pipeline/src/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ export {
3030
} from "./pipeline";
3131
export {
3232
createPipelineFromOptions,
33+
TelemetryOptions,
3334
InternalPipelineOptions,
3435
PipelineOptions,
3536
} from "./createPipelineFromOptions";
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
// Copyright (c) Microsoft Corporation.
2+
// Licensed under the MIT license.
3+
4+
import { assert } from "chai";
5+
import * as sinon from "sinon";
6+
import {
7+
HttpClient,
8+
PipelineResponse,
9+
SendRequest,
10+
createHttpHeaders,
11+
createPipelineFromOptions,
12+
createPipelineRequest,
13+
setClientRequestIdPolicy,
14+
} from "../src";
15+
16+
describe("setClientRequestIdPolicy", function () {
17+
afterEach(function () {
18+
sinon.restore();
19+
});
20+
21+
it("should set the header name with `x-ms-client-request-id` if no header name is provided", async () => {
22+
const request = createPipelineRequest({
23+
url: "https://bing.com",
24+
});
25+
const policy = setClientRequestIdPolicy();
26+
const successResponse: PipelineResponse = {
27+
headers: createHttpHeaders(),
28+
request,
29+
status: 200,
30+
};
31+
const next = sinon.stub<Parameters<SendRequest>, ReturnType<SendRequest>>();
32+
next.onFirstCall().resolves(successResponse);
33+
assert.isFalse(request.headers.has("x-ms-client-request-id"));
34+
await policy.sendRequest(request, next);
35+
assert.isTrue(request.headers.has("x-ms-client-request-id"));
36+
});
37+
38+
it("should set the header name with `x-ms-client-request-id` if commonTelemetryOptions is empty", async () => {
39+
const pipeline = createPipelineFromOptions({
40+
telemetryOptions: {},
41+
});
42+
const pipelineRequest = createPipelineRequest({
43+
url: "https://bing.com",
44+
});
45+
const httpClient: HttpClient = {
46+
sendRequest: async (request) => {
47+
assert.isTrue(request.headers.has("x-ms-client-request-id"));
48+
assert.equal(request.headers.get("x-ms-client-request-id"), request.requestId);
49+
return {
50+
request,
51+
headers: createHttpHeaders(),
52+
status: 200,
53+
};
54+
},
55+
};
56+
assert.isFalse(pipelineRequest.headers.has("x-ms-client-request-id"));
57+
await pipeline.sendRequest(httpClient, pipelineRequest);
58+
});
59+
60+
it("should set the header with custom header name if it is provided", async () => {
61+
const customHeaderName = "custom-client-request-id";
62+
const pipeline = createPipelineFromOptions({
63+
telemetryOptions: {
64+
clientRequestIdHeaderName: customHeaderName,
65+
},
66+
});
67+
const pipelineRequest = createPipelineRequest({
68+
url: "https://bing.com",
69+
});
70+
const httpClient: HttpClient = {
71+
sendRequest: async (request) => {
72+
assert.isTrue(request.headers.has(customHeaderName));
73+
assert.equal(request.headers.get(customHeaderName), request.requestId);
74+
return {
75+
request,
76+
headers: createHttpHeaders(),
77+
status: 200,
78+
};
79+
},
80+
};
81+
assert.isFalse(pipelineRequest.headers.has("x-ms-client-request-id"));
82+
assert.isFalse(pipelineRequest.headers.has(customHeaderName));
83+
await pipeline.sendRequest(httpClient, pipelineRequest);
84+
});
85+
});

0 commit comments

Comments
 (0)