Skip to content

Commit

Permalink
Add some other request options (#26331)
Browse files Browse the repository at this point in the history
fixes Azure/autorest.typescript#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;
}
```
  • Loading branch information
qiaozha authored Jun 30, 2023
1 parent 8880ca7 commit e24d085
Show file tree
Hide file tree
Showing 7 changed files with 207 additions and 5 deletions.
7 changes: 2 additions & 5 deletions sdk/core/core-client-rest/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand Down
2 changes: 2 additions & 0 deletions sdk/core/core-client-rest/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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": {
Expand Down
42 changes: 42 additions & 0 deletions sdk/core/core-client-rest/review/core-client.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,22 @@

/// <reference types="node" />

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;
Expand Down Expand Up @@ -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;

Expand Down Expand Up @@ -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 string> = TRoute extends `${infer _Head}/{${infer _Param}}${infer Tail}` ? [
pathParameter: string,
Expand All @@ -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;
Expand All @@ -126,6 +162,12 @@ export type RequestParameters = {
allowInsecureConnection?: boolean;
skipUrlEncoding?: boolean;
pathParameters?: Record<string, any>;
timeout?: number;
onUploadProgress?: (progress: TransferProgressEvent) => void;
onDownloadProgress?: (progress: TransferProgressEvent) => void;
abortSignal?: AbortSignalLike;
tracingOptions?: OperationTracingOptions;
onResponse?: RawResponseCallback;
};

// @public
Expand Down
126 changes: 126 additions & 0 deletions sdk/core/core-client-rest/src/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -48,8 +53,129 @@ export type RequestParameters = {
* Path parameters for custom the base url
*/
pathParameters?: Record<string, any>;

/**
* 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
*/
Expand Down
1 change: 1 addition & 0 deletions sdk/core/core-client-rest/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,6 @@

export { createRestError } from "./restError";
export { addCredentialPipelinePolicy, AddCredentialPipelinePolicyOptions } from "./clientHelpers";
export { operationOptionsToRequestParameters } from "./operationOptionHelpers";
export * from "./getClient";
export * from "./common";
23 changes: 23 additions & 0 deletions sdk/core/core-client-rest/src/operationOptionHelpers.ts
Original file line number Diff line number Diff line change
@@ -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,
};
}
11 changes: 11 additions & 0 deletions sdk/core/core-client-rest/src/sendRequest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,11 +37,17 @@ export async function sendRequest(
): Promise<HttpResponse> {
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,
Expand Down Expand Up @@ -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])
Expand Down

0 comments on commit e24d085

Please sign in to comment.