Skip to content

Commit

Permalink
Convert core-http to use interfaces for requests (Azure#7873)
Browse files Browse the repository at this point in the history
* Convert core-http to use interfaces for requests
* Update version and CHANGELOG
  • Loading branch information
xirzec committed Mar 21, 2020
1 parent cac2180 commit 4555a45
Show file tree
Hide file tree
Showing 34 changed files with 333 additions and 131 deletions.
8 changes: 5 additions & 3 deletions sdk/core/core-http/CHANGELOG.md
@@ -1,19 +1,21 @@
# Release History

## 1.0.5 (Unreleased)
## 1.1.0 (Unreleased)

- A new interface `WebResourceLike` was introduced to avoid a direct dependency on the class `WebResource` in public interfaces. `HttpHeadersLike` was also added to replace references to `HttpHeaders`. This should improve cross-version compatibility for core-http. [PR #7873](https://github.com/Azure/azure-sdk-for-js/pull/7873)

## 1.0.4 (2020-03-03)

- When an operation times out based on the `timeout` configured in the `OperationRequestOptions`, it gets terminated with an error. In this update, the error that is thrown in browser for such cases is updated to match what is thrown in node i.e an `AbortError` is thrown instead of the previous `RestError`. [PR #7159](https://github.com/Azure/azure-sdk-for-js/pull/7159)
- Support for username and password in the proxy url [PR #7211](https://github.com/Azure/azure-sdk-for-js/pull/7211)
- Removed dependency on `lib.dom.d.ts` so TypeScript users no longer need `lib: ["dom"]` in their tsconfig.json file to use this library. [PR #7500](https://github.com/Azure/azure-sdk-for-js/pull/7500)
- Removed dependency on `lib.dom.d.ts` so TypeScript users no longer need `lib: ["dom"]` in their tsconfig.json file to use this library. [PR #7500](https://github.com/Azure/azure-sdk-for-js/pull/7500)

## 1.0.3 (2020-01-02)

- Added `x-ms-useragent` to the list of allowed headers in request logs.
- Fix issue of data being pushed twice when reporting progress ([PR #6427](https://github.com/Azure/azure-sdk-for-js/issues/6427))
- Move `getDefaultProxySettings()` calls into `proxyPolicy` so that libraries that don't use the PipelineOptions or createDefaultRequestPolicyFactories from core-http can use this behavior without duplicating code. ([PR #6478](https://github.com/Azure/azure-sdk-for-js/issues/6478))
- Fix tracingPolicy() to set standard span attributes ([PR #6565](https://github.com/Azure/azure-sdk-for-js/pull/6565)). Now the following are set correctly for the spans
- Fix tracingPolicy() to set standard span attributes ([PR #6565](https://github.com/Azure/azure-sdk-for-js/pull/6565)). Now the following are set correctly for the spans
- `http.method`
- `http.url`
- `http.user_agent`
Expand Down
2 changes: 1 addition & 1 deletion sdk/core/core-http/package.json
Expand Up @@ -6,7 +6,7 @@
"email": "azsdkteam@microsoft.com",
"url": "https://github.com/Azure/azure-sdk-for-js"
},
"version": "1.0.5",
"version": "1.1.0",
"description": "Isomorphic client Runtime for Typescript/node.js/browser javascript client libraries generated using AutoRest",
"tags": [
"isomorphic",
Expand Down
4 changes: 2 additions & 2 deletions sdk/core/core-http/src/browserFetchHttpClient.ts
Expand Up @@ -3,10 +3,10 @@

import { FetchHttpClient, CommonRequestInfo } from "./fetchHttpClient";
import { HttpOperationResponse } from "./httpOperationResponse";
import { WebResource } from "./webResource";
import { WebResourceLike } from "./webResource";

export class BrowserFetchHttpClient extends FetchHttpClient {
prepareRequest(_httpRequest: WebResource): Promise<Partial<RequestInit>> {
prepareRequest(_httpRequest: WebResourceLike): Promise<Partial<RequestInit>> {
return Promise.resolve({});
}

Expand Down
3 changes: 2 additions & 1 deletion sdk/core/core-http/src/coreHttp.ts
Expand Up @@ -5,6 +5,7 @@

export {
WebResource,
WebResourceLike,
HttpRequestBody,
RequestPrepareOptions,
HttpMethods,
Expand All @@ -14,7 +15,7 @@ export {
} from "./webResource";
export { DefaultHttpClient } from "./defaultHttpClient";
export { HttpClient } from "./httpClient";
export { HttpHeaders } from "./httpHeaders";
export { HttpHeaders, HttpHeadersLike } from "./httpHeaders";
export { HttpOperationResponse, HttpResponse, RestResponse } from "./httpOperationResponse";
export { HttpPipelineLogger } from "./httpPipelineLogger";
export { HttpPipelineLogLevel } from "./httpPipelineLogLevel";
Expand Down
8 changes: 4 additions & 4 deletions sdk/core/core-http/src/credentials/apiKeyCredentials.ts
Expand Up @@ -2,7 +2,7 @@
// Licensed under the MIT License.

import { HttpHeaders } from "../httpHeaders";
import { WebResource } from "../webResource";
import { WebResourceLike } from "../webResource";
import { ServiceClientCredentials } from "./serviceClientCredentials";

/**
Expand Down Expand Up @@ -50,10 +50,10 @@ export class ApiKeyCredentials implements ServiceClientCredentials {
/**
* Signs a request with the values provided in the inHeader and inQuery parameter.
*
* @param {WebResource} webResource The WebResource to be signed.
* @returns {Promise<WebResource>} The signed request object.
* @param {WebResourceLike} webResource The WebResourceLike to be signed.
* @returns {Promise<WebResourceLike>} The signed request object.
*/
signRequest(webResource: WebResource): Promise<WebResource> {
signRequest(webResource: WebResourceLike): Promise<WebResourceLike> {
if (!webResource) {
return Promise.reject(
new Error(`webResource cannot be null or undefined and must be of type "object".`)
Expand Down
Expand Up @@ -4,7 +4,7 @@
import { HttpHeaders } from "../httpHeaders";
import * as base64 from "../util/base64";
import { Constants } from "../util/constants";
import { WebResource } from "../webResource";
import { WebResourceLike } from "../webResource";
import { ServiceClientCredentials } from "./serviceClientCredentials";
const HeaderConstants = Constants.HeaderConstants;
const DEFAULT_AUTHORIZATION_SCHEME = "Basic";
Expand Down Expand Up @@ -41,10 +41,10 @@ export class BasicAuthenticationCredentials implements ServiceClientCredentials
/**
* Signs a request with the Authentication header.
*
* @param {WebResource} webResource The WebResource to be signed.
* @returns {Promise<WebResource>} The signed request object.
* @param {WebResourceLike} webResource The WebResourceLike to be signed.
* @returns {Promise<WebResourceLike>} The signed request object.
*/
signRequest(webResource: WebResource) {
signRequest(webResource: WebResourceLike) {
const credentials = `${this.userName}:${this.password}`;
const encodedCredentials = `${this.authorizationScheme} ${base64.encodeString(credentials)}`;
if (!webResource.headers) webResource.headers = new HttpHeaders();
Expand Down
@@ -1,14 +1,14 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

import { WebResource } from "../webResource";
import { WebResourceLike } from "../webResource";

export interface ServiceClientCredentials {
/**
* Signs a request with the Authentication header.
*
* @param {WebResource} webResource The WebResource/request to be signed.
* @returns {Promise<WebResource>} The signed request object;
* @param {WebResourceLike} webResource The WebResourceLike/request to be signed.
* @returns {Promise<WebResourceLike>} The signed request object;
*/
signRequest(webResource: WebResource): Promise<WebResource>;
signRequest(webResource: WebResourceLike): Promise<WebResourceLike>;
}
12 changes: 6 additions & 6 deletions sdk/core/core-http/src/fetchHttpClient.ts
Expand Up @@ -5,9 +5,9 @@ import { AbortController, AbortError } from "@azure/abort-controller";
import FormData from "form-data";

import { HttpClient } from "./httpClient";
import { TransferProgressEvent, WebResource } from "./webResource";
import { TransferProgressEvent, WebResourceLike } from "./webResource";
import { HttpOperationResponse } from "./httpOperationResponse";
import { HttpHeaders } from "./httpHeaders";
import { HttpHeaders, HttpHeadersLike } from "./httpHeaders";
import { RestError } from "./restError";
import { Readable, Transform } from "stream";

Expand All @@ -34,10 +34,10 @@ export class ReportTransform extends Transform {
}

export abstract class FetchHttpClient implements HttpClient {
async sendRequest(httpRequest: WebResource): Promise<HttpOperationResponse> {
async sendRequest(httpRequest: WebResourceLike): Promise<HttpOperationResponse> {
if (!httpRequest && typeof httpRequest !== "object") {
throw new Error(
"'httpRequest' (WebResource) cannot be null or undefined and must be of type object."
"'httpRequest' (WebResourceLike) cannot be null or undefined and must be of type object."
);
}

Expand Down Expand Up @@ -188,7 +188,7 @@ export abstract class FetchHttpClient implements HttpClient {
}
}

abstract async prepareRequest(httpRequest: WebResource): Promise<Partial<RequestInit>>;
abstract async prepareRequest(httpRequest: WebResourceLike): Promise<Partial<RequestInit>>;
abstract async processRequest(operationResponse: HttpOperationResponse): Promise<void>;
abstract async fetch(input: CommonRequestInfo, init?: RequestInit): Promise<Response>;
}
Expand All @@ -197,7 +197,7 @@ function isReadableStream(body: any): body is Readable {
return body && typeof body.pipe === "function";
}

export function parseHeaders(headers: Headers): HttpHeaders {
export function parseHeaders(headers: Headers): HttpHeadersLike {
const httpHeaders = new HttpHeaders();

headers.forEach((value, key) => {
Expand Down
80 changes: 78 additions & 2 deletions sdk/core/core-http/src/httpHeaders.ts
Expand Up @@ -31,7 +31,83 @@ export type RawHttpHeaders = { [headerName: string]: string };
/**
* A collection of HTTP header key/value pairs.
*/
export class HttpHeaders {
export interface HttpHeadersLike {
/**
* Set a header in this collection with the provided name and value. The name is
* case-insensitive.
* @param headerName The name of the header to set. This value is case-insensitive.
* @param headerValue The value of the header to set.
*/
set(headerName: string, headerValue: string | number): void;
/**
* Get the header value for the provided header name, or undefined if no header exists in this
* collection with the provided name.
* @param headerName The name of the header.
*/
get(headerName: string): string | undefined;
/**
* Get whether or not this header collection contains a header entry for the provided header name.
*/
contains(headerName: string): boolean;
/**
* Remove the header with the provided headerName. Return whether or not the header existed and
* was removed.
* @param headerName The name of the header to remove.
*/
remove(headerName: string): boolean;
/**
* Get the headers that are contained this collection as an object.
*/
rawHeaders(): RawHttpHeaders;
/**
* Get the headers that are contained in this collection as an array.
*/
headersArray(): HttpHeader[];
/**
* Get the header names that are contained in this collection.
*/
headerNames(): string[];
/**
* Get the header values that are contained in this collection.
*/
headerValues(): string[];
/**
* Create a deep clone/copy of this HttpHeaders collection.
*/
clone(): HttpHeadersLike;
/**
* Get the JSON object representation of this HTTP header collection.
* The result is the same as `rawHeaders()`.
*/
toJson(): RawHttpHeaders;
}

export function isHttpHeadersLike(object?: any): object is HttpHeadersLike {
if (!object || typeof object !== "object") {
return false;
}

if (
typeof object.rawHeaders === "function" &&
typeof object.clone === "function" &&
typeof object.get === "function" &&
typeof object.set === "function" &&
typeof object.contains === "function" &&
typeof object.remove === "function" &&
typeof object.headersArray === "function" &&
typeof object.headerValues === "function" &&
typeof object.headerNames === "function" &&
typeof object.toJson === "function"
) {
return true;
}
return false;
}

/**
* A collection of HTTP header key/value pairs.
*/
export class HttpHeaders implements HttpHeadersLike {
private readonly _headersMap: { [headerKey: string]: HttpHeader };

constructor(rawHeaders?: RawHttpHeaders) {
Expand Down Expand Up @@ -120,7 +196,7 @@ export class HttpHeaders {
}

/**
* Get the header names that are contained in this collection.
* Get the header values that are contained in this collection.
*/
public headerValues(): string[] {
const headerValues: string[] = [];
Expand Down
8 changes: 4 additions & 4 deletions sdk/core/core-http/src/httpOperationResponse.ts
@@ -1,8 +1,8 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

import { WebResource } from "./webResource";
import { HttpHeaders } from "./httpHeaders";
import { WebResourceLike } from "./webResource";
import { HttpHeadersLike } from "./httpHeaders";

/**
* The properties on an HTTP response which will always be present.
Expand All @@ -11,7 +11,7 @@ export interface HttpResponse {
/**
* The raw request
*/
request: WebResource;
request: WebResourceLike;

/**
* The HTTP response status (e.g. 200)
Expand All @@ -21,7 +21,7 @@ export interface HttpResponse {
/**
* The HTTP response headers.
*/
headers: HttpHeaders;
headers: HttpHeadersLike;
}

declare global {
Expand Down
6 changes: 3 additions & 3 deletions sdk/core/core-http/src/nodeFetchHttpClient.ts
Expand Up @@ -8,7 +8,7 @@ import "node-fetch";

import { FetchHttpClient, CommonRequestInfo } from "./fetchHttpClient";
import { HttpOperationResponse } from "./httpOperationResponse";
import { WebResource } from "./webResource";
import { WebResourceLike } from "./webResource";
import { createProxyAgent, ProxyAgent, isUrlHttps } from "./proxyAgent";

interface GlobalWithFetch extends NodeJS.Global {
Expand Down Expand Up @@ -39,7 +39,7 @@ export class NodeFetchHttpClient extends FetchHttpClient {

private readonly cookieJar = new tough.CookieJar(undefined, { looseMode: true });

private getOrCreateAgent(httpRequest: WebResource): http.Agent | https.Agent {
private getOrCreateAgent(httpRequest: WebResourceLike): http.Agent | https.Agent {
const isHttps = isUrlHttps(httpRequest.url);

// At the moment, proxy settings and keepAlive are mutually
Expand Down Expand Up @@ -91,7 +91,7 @@ export class NodeFetchHttpClient extends FetchHttpClient {
return fetch(input, init);
}

async prepareRequest(httpRequest: WebResource): Promise<Partial<RequestInit>> {
async prepareRequest(httpRequest: WebResourceLike): Promise<Partial<RequestInit>> {
const requestInit: Partial<RequestInit & { agent?: any }> = {};

if (this.cookieJar && !httpRequest.headers.get("Cookie")) {
Expand Down
Expand Up @@ -11,7 +11,7 @@ import {
import { Constants } from "../util/constants";
import { HttpOperationResponse } from "../httpOperationResponse";
import { HttpHeaders } from "../httpHeaders";
import { WebResource } from "../webResource";
import { WebResourceLike } from "../webResource";
import { AccessTokenCache, ExpiringAccessTokenCache } from "../credentials/accessTokenCache";

/**
Expand Down Expand Up @@ -69,7 +69,7 @@ export class BearerTokenAuthenticationPolicy extends BaseRequestPolicy {
* Applies the Bearer token to the request through the Authorization header.
* @param webResource
*/
public async sendRequest(webResource: WebResource): Promise<HttpOperationResponse> {
public async sendRequest(webResource: WebResourceLike): Promise<HttpOperationResponse> {
if (!webResource.headers) webResource.headers = new HttpHeaders();
const token = await this.getToken({
abortSignal: webResource.abortSignal,
Expand Down
6 changes: 3 additions & 3 deletions sdk/core/core-http/src/policies/deserializationPolicy.ts
Expand Up @@ -7,7 +7,7 @@ import { OperationSpec, isStreamOperation } from "../operationSpec";
import { RestError } from "../restError";
import { MapperType } from "../serializer";
import { parseXML } from "../util/xml";
import { WebResource } from "../webResource";
import { WebResourceLike } from "../webResource";
import {
BaseRequestPolicy,
RequestPolicy,
Expand Down Expand Up @@ -89,7 +89,7 @@ export class DeserializationPolicy extends BaseRequestPolicy {
(deserializationContentTypes && deserializationContentTypes.xml) || defaultXmlContentTypes;
}

public async sendRequest(request: WebResource): Promise<HttpOperationResponse> {
public async sendRequest(request: WebResourceLike): Promise<HttpOperationResponse> {
return this._nextPolicy
.sendRequest(request)
.then((response: HttpOperationResponse) =>
Expand All @@ -102,7 +102,7 @@ function getOperationResponse(
parsedResponse: HttpOperationResponse
): undefined | OperationResponse {
let result: OperationResponse | undefined;
const request: WebResource = parsedResponse.request;
const request: WebResourceLike = parsedResponse.request;
const operationSpec: OperationSpec | undefined = request.operationSpec;
if (operationSpec) {
const operationResponseGetter:
Expand Down

0 comments on commit 4555a45

Please sign in to comment.