From e24d0855454188cedaf5e48c6507650500b823f8 Mon Sep 17 00:00:00 2001 From: Qiaoqiao Zhang <55688292+qiaozha@users.noreply.github.com> Date: Fri, 30 Jun 2023 08:34:24 +0800 Subject: [PATCH] Add some other request options (#26331) fixes https://github.com/Azure/autorest.typescript/issues/1902 This PR is trying to map the [OperationOptions](https://github.com/Azure/azure-sdk-for-js/blob/main/sdk/core/core-client/src/interfaces.ts#L98-L122) from @azure/core-client to [RequestParameters](https://github.com/Azure/azure-sdk-for-js/blob/main/sdk/core/core-client-rest/src/common.ts#L19-L51) in @azure-rest/core-client. As the API layer internally call rest layer, we should provide every functionality that the high level core-client @azure-rest/core-client has and map them to the rest level core-client @azure-rest/core-client. right now I have added `abortSignal`, `tracingOptions`, `onResponse` into the RequestParameters. ```typescript /** * The signal which can be used to abort requests. */ abortSignal?: AbortSignalLike; /** * Options used when tracing is enabled. */ tracingOptions?: OperationTracingOptions; /** * A function to be called each time a response is received from the server * while performing the requested operation. * May be called multiple times. */ onResponse?: RawResponseCallback; ``` And inside the `requestOptions`, I have added `timeout`, `onUploadProgress`, `onDownloadProgress` and flattened it in the top level of `RequestParameters` ```typescript /** * The number of milliseconds a request can take before automatically being terminated. */ timeout?: number; /** * Callback which fires upon upload progress. */ onUploadProgress?: (progress: TransferProgressEvent) => void; /** * Callback which fires upon download progress. */ onDownloadProgress?: (progress: TransferProgressEvent) => void; ``` Also, add an interface OperationOptions in @azure-rest/core-client, for modular usage in specify these options. ```typescript export interface OperationOptions { /** * The signal which can be used to abort requests. */ abortSignal?: AbortSignalLike; /** * Options used when creating and sending HTTP requests for this operation. */ requestOptions?: OperationRequestOptions; /** * Options used when tracing is enabled. */ tracingOptions?: OperationTracingOptions; /** * A function to be called each time a response is received from the server * while performing the requested operation. * May be called multiple times. */ onResponse?: RawResponseCallback; } ``` --- sdk/core/core-client-rest/CHANGELOG.md | 7 +- sdk/core/core-client-rest/package.json | 2 + .../review/core-client.api.md | 42 ++++++ sdk/core/core-client-rest/src/common.ts | 126 ++++++++++++++++++ sdk/core/core-client-rest/src/index.ts | 1 + .../src/operationOptionHelpers.ts | 23 ++++ sdk/core/core-client-rest/src/sendRequest.ts | 11 ++ 7 files changed, 207 insertions(+), 5 deletions(-) create mode 100644 sdk/core/core-client-rest/src/operationOptionHelpers.ts diff --git a/sdk/core/core-client-rest/CHANGELOG.md b/sdk/core/core-client-rest/CHANGELOG.md index 424e5e8d36ae..0a0382bfc524 100644 --- a/sdk/core/core-client-rest/CHANGELOG.md +++ b/sdk/core/core-client-rest/CHANGELOG.md @@ -4,11 +4,8 @@ ### Features Added -### Breaking Changes - -### Bugs Fixed - -### Other Changes +- Add `timeout`, `onUploadProgress`, `onDownloadProgress`, `abortSignal`, `tracingOptions`, `onResponse` in the `RequestParameters` for better RLC user experience. +- Add `OperationOptions` for better modular user experience. ## 1.1.3 (2023-05-04) diff --git a/sdk/core/core-client-rest/package.json b/sdk/core/core-client-rest/package.json index b607bcbf26b8..8d1f7f911bd5 100644 --- a/sdk/core/core-client-rest/package.json +++ b/sdk/core/core-client-rest/package.json @@ -59,6 +59,8 @@ "@azure/core-auth": "^1.3.0", "@azure/core-rest-pipeline": "^1.5.0", "@azure/core-util": "^1.0.0", + "@azure/abort-controller": "^1.1.0", + "@azure/core-tracing": "^1.0.1", "tslib": "^2.2.0" }, "devDependencies": { diff --git a/sdk/core/core-client-rest/review/core-client.api.md b/sdk/core/core-client-rest/review/core-client.api.md index 8e936042b204..be4721f43513 100644 --- a/sdk/core/core-client-rest/review/core-client.api.md +++ b/sdk/core/core-client-rest/review/core-client.api.md @@ -6,17 +6,22 @@ /// +import { AbortSignalLike } from '@azure/abort-controller'; import { HttpClient } from '@azure/core-rest-pipeline'; import { KeyCredential } from '@azure/core-auth'; import { LogPolicyOptions } from '@azure/core-rest-pipeline'; +import { OperationTracingOptions } from '@azure/core-tracing'; import { Pipeline } from '@azure/core-rest-pipeline'; import { PipelineOptions } from '@azure/core-rest-pipeline'; import { PipelinePolicy } from '@azure/core-rest-pipeline'; import { PipelineRequest } from '@azure/core-rest-pipeline'; +import { PipelineResponse } from '@azure/core-rest-pipeline'; import { RawHttpHeaders } from '@azure/core-rest-pipeline'; import { RawHttpHeadersInput } from '@azure/core-rest-pipeline'; +import { RequestBodyType } from '@azure/core-rest-pipeline'; import { RestError } from '@azure/core-rest-pipeline'; import { TokenCredential } from '@azure/core-auth'; +import { TransferProgressEvent } from '@azure/core-rest-pipeline'; // @public export function addCredentialPipelinePolicy(pipeline: Pipeline, baseUrl: string, options?: AddCredentialPipelinePolicyOptions): void; @@ -71,6 +76,13 @@ export interface ErrorResponse { error: ErrorModel; } +// @public +export interface FullOperationResponse extends PipelineResponse { + parsedBody?: RequestBodyType; + rawHeaders?: RawHttpHeaders; + request: PipelineRequest; +} + // @public export function getClient(baseUrl: string, options?: ClientOptions): Client; @@ -101,6 +113,27 @@ export interface InnerError { innererror?: InnerError; } +// @public +export interface OperationOptions { + abortSignal?: AbortSignalLike; + onResponse?: RawResponseCallback; + requestOptions?: OperationRequestOptions; + tracingOptions?: OperationTracingOptions; +} + +// @public +export function operationOptionsToRequestParameters(options: OperationOptions): RequestParameters; + +// @public +export interface OperationRequestOptions { + allowInsecureConnection?: boolean; + headers?: RawHttpHeadersInput; + onDownloadProgress?: (progress: TransferProgressEvent) => void; + onUploadProgress?: (progress: TransferProgressEvent) => void; + skipUrlEncoding?: boolean; + timeout?: number; +} + // @public export type PathParameters = TRoute extends `${infer _Head}/{${infer _Param}}${infer Tail}` ? [ pathParameter: string, @@ -116,6 +149,9 @@ export type PathUncheckedResponse = HttpResponse & { body: any; }; +// @public +export type RawResponseCallback = (rawResponse: FullOperationResponse, error?: unknown) => void; + // @public export type RequestParameters = { headers?: RawHttpHeadersInput; @@ -126,6 +162,12 @@ export type RequestParameters = { allowInsecureConnection?: boolean; skipUrlEncoding?: boolean; pathParameters?: Record; + timeout?: number; + onUploadProgress?: (progress: TransferProgressEvent) => void; + onDownloadProgress?: (progress: TransferProgressEvent) => void; + abortSignal?: AbortSignalLike; + tracingOptions?: OperationTracingOptions; + onResponse?: RawResponseCallback; }; // @public diff --git a/sdk/core/core-client-rest/src/common.ts b/sdk/core/core-client-rest/src/common.ts index 2e2b82df8dde..c2f3f51bc210 100644 --- a/sdk/core/core-client-rest/src/common.ts +++ b/sdk/core/core-client-rest/src/common.ts @@ -8,9 +8,14 @@ import { PipelineOptions, PipelinePolicy, PipelineRequest, + PipelineResponse, RawHttpHeaders, + RequestBodyType, + TransferProgressEvent, } from "@azure/core-rest-pipeline"; import { RawHttpHeadersInput } from "@azure/core-rest-pipeline"; +import { AbortSignalLike } from "@azure/abort-controller"; +import { OperationTracingOptions } from "@azure/core-tracing"; /** * Shape of the default request parameters, this may be overriden by the specific @@ -48,8 +53,129 @@ export type RequestParameters = { * Path parameters for custom the base url */ pathParameters?: Record; + + /** + * The number of milliseconds a request can take before automatically being terminated. + */ + timeout?: number; + + /** + * Callback which fires upon upload progress. + */ + onUploadProgress?: (progress: TransferProgressEvent) => void; + + /** + * Callback which fires upon download progress. + */ + onDownloadProgress?: (progress: TransferProgressEvent) => void; + + /** + * The signal which can be used to abort requests. + */ + abortSignal?: AbortSignalLike; + + /** + * Options used when tracing is enabled. + */ + tracingOptions?: OperationTracingOptions; + + /** + * A function to be called each time a response is received from the server + * while performing the requested operation. + * May be called multiple times. + */ + onResponse?: RawResponseCallback; }; +/** + * A function to be called each time a response is received from the server + * while performing the requested operation. + * May be called multiple times. + */ +export type RawResponseCallback = (rawResponse: FullOperationResponse, error?: unknown) => void; + +/** + * Wrapper object for http request and response. Deserialized object is stored in + * the `parsedBody` property when the response body is received in JSON. + */ +export interface FullOperationResponse extends PipelineResponse { + /** + * The raw HTTP response headers. + */ + rawHeaders?: RawHttpHeaders; + + /** + * The response body as parsed JSON. + */ + parsedBody?: RequestBodyType; + + /** + * The request that generated the response. + */ + request: PipelineRequest; +} + +/** + * The base options type for all operations. + */ +export interface OperationOptions { + /** + * The signal which can be used to abort requests. + */ + abortSignal?: AbortSignalLike; + /** + * Options used when creating and sending HTTP requests for this operation. + */ + requestOptions?: OperationRequestOptions; + /** + * Options used when tracing is enabled. + */ + tracingOptions?: OperationTracingOptions; + + /** + * A function to be called each time a response is received from the server + * while performing the requested operation. + * May be called multiple times. + */ + onResponse?: RawResponseCallback; +} + +/** + * Options used when creating and sending HTTP requests for this operation. + */ +export interface OperationRequestOptions { + /** + * User defined custom request headers that + * will be applied before the request is sent. + */ + headers?: RawHttpHeadersInput; + + /** + * The number of milliseconds a request can take before automatically being terminated. + */ + timeout?: number; + + /** + * Callback which fires upon upload progress. + */ + onUploadProgress?: (progress: TransferProgressEvent) => void; + + /** + * Callback which fires upon download progress. + */ + onDownloadProgress?: (progress: TransferProgressEvent) => void; + + /** + * Set to true if the request is sent over HTTP instead of HTTPS + */ + allowInsecureConnection?: boolean; + + /** + * Set to true if you want to skip encoding the path parameters + */ + skipUrlEncoding?: boolean; +} + /** * Type to use with pathUnchecked, overrides the body type to any to allow flexibility */ diff --git a/sdk/core/core-client-rest/src/index.ts b/sdk/core/core-client-rest/src/index.ts index 1af1becfebd4..046849c9f07b 100644 --- a/sdk/core/core-client-rest/src/index.ts +++ b/sdk/core/core-client-rest/src/index.ts @@ -8,5 +8,6 @@ export { createRestError } from "./restError"; export { addCredentialPipelinePolicy, AddCredentialPipelinePolicyOptions } from "./clientHelpers"; +export { operationOptionsToRequestParameters } from "./operationOptionHelpers"; export * from "./getClient"; export * from "./common"; diff --git a/sdk/core/core-client-rest/src/operationOptionHelpers.ts b/sdk/core/core-client-rest/src/operationOptionHelpers.ts new file mode 100644 index 000000000000..21cb63127a52 --- /dev/null +++ b/sdk/core/core-client-rest/src/operationOptionHelpers.ts @@ -0,0 +1,23 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +import { OperationOptions, RequestParameters } from "./common"; + +/** + * Helper function to convert OperationOptions to RequestParameters + * @param options - the options that are used by Modular layer to send the request + * @returns the result of the conversion in RequestParameters of RLC layer + */ +export function operationOptionsToRequestParameters(options: OperationOptions): RequestParameters { + return { + allowInsecureConnection: options.requestOptions?.allowInsecureConnection, + timeout: options.requestOptions?.timeout, + skipUrlEncoding: options.requestOptions?.skipUrlEncoding, + abortSignal: options.abortSignal, + onUploadProgress: options.requestOptions?.onUploadProgress, + onDownloadProgress: options.requestOptions?.onDownloadProgress, + tracingOptions: options.tracingOptions, + headers: { ...options.requestOptions?.headers }, + onResponse: options.onResponse, + }; +} diff --git a/sdk/core/core-client-rest/src/sendRequest.ts b/sdk/core/core-client-rest/src/sendRequest.ts index 4c90da57b7e8..641b0a9b8178 100644 --- a/sdk/core/core-client-rest/src/sendRequest.ts +++ b/sdk/core/core-client-rest/src/sendRequest.ts @@ -37,11 +37,17 @@ export async function sendRequest( ): Promise { const httpClient = customHttpClient ?? getCachedDefaultHttpsClient(); const request = buildPipelineRequest(method, url, options); + const response = await pipeline.sendRequest(httpClient, request); + const rawHeaders: RawHttpHeaders = response.headers.toJSON(); const parsedBody: RequestBodyType | undefined = getResponseBody(response); + if (options?.onResponse) { + options.onResponse({ ...response, request, rawHeaders, parsedBody }); + } + return { request, headers: rawHeaders, @@ -127,6 +133,11 @@ function buildPipelineRequest( formData, headers, allowInsecureConnection: options.allowInsecureConnection, + tracingOptions: options.tracingOptions, + abortSignal: options.abortSignal, + onUploadProgress: options.onUploadProgress, + onDownloadProgress: options.onDownloadProgress, + timeout: options.timeout, enableBrowserStreams: true, streamResponseStatusCodes: options.responseAsStream ? new Set([Number.POSITIVE_INFINITY])