diff --git a/src/NotebookWorkspaceManager/NotebookWorkspaceManager.ts b/src/NotebookWorkspaceManager/NotebookWorkspaceManager.ts index fc2b144f8..cb2b5076a 100644 --- a/src/NotebookWorkspaceManager/NotebookWorkspaceManager.ts +++ b/src/NotebookWorkspaceManager/NotebookWorkspaceManager.ts @@ -83,7 +83,9 @@ export class NotebookWorkspaceManager implements ViewModels.NotebookWorkspaceMan public async startNotebookWorkspaceAsync(cosmosdbResourceId: string, notebookWorkspaceId: string): Promise { const uri = `${cosmosdbResourceId}/notebookWorkspaces/${notebookWorkspaceId}/start`; try { - return await this.rpClient(uri).postAsync(uri, ArmApiVersions.documentDB, undefined); + return await this.rpClient(uri).postAsync(uri, ArmApiVersions.documentDB, undefined, { + skipResourceValidation: true + }); } catch (error) { Logger.logError(error, "NotebookWorkspaceManager/startNotebookWorkspaceAsync"); throw error; diff --git a/src/ResourceProvider/IResourceProviderClient.ts b/src/ResourceProvider/IResourceProviderClient.ts index 43c13edd5..b9205be4b 100644 --- a/src/ResourceProvider/IResourceProviderClient.ts +++ b/src/ResourceProvider/IResourceProviderClient.ts @@ -1,9 +1,28 @@ export interface IResourceProviderClient { - deleteAsync(url: string, apiVersion: string): Promise; - getAsync(url: string, apiVersion: string, queryString?: string): Promise; - postAsync(url: string, apiVersion: string, body: any): Promise; - putAsync(url: string, apiVersion: string, body: any): Promise; - patchAsync(url: string, apiVersion: string, body: any): Promise; + deleteAsync(url: string, apiVersion: string, requestOptions?: IResourceProviderRequestOptions): Promise; + getAsync( + url: string, + apiVersion: string, + queryString?: string, + requestOptions?: IResourceProviderRequestOptions + ): Promise; + postAsync(url: string, apiVersion: string, body: any, requestOptions?: IResourceProviderRequestOptions): Promise; + putAsync( + url: string, + apiVersion: string, + body: any, + requestOptions?: IResourceProviderRequestOptions + ): Promise; + patchAsync( + url: string, + apiVersion: string, + body: any, + requestOptions?: IResourceProviderRequestOptions + ): Promise; +} + +export interface IResourceProviderRequestOptions { + skipResourceValidation: boolean; } export interface IResourceProviderClientFactory { diff --git a/src/ResourceProvider/ResourceProviderClient.ts b/src/ResourceProvider/ResourceProviderClient.ts index 05a5247bb..b0828374f 100644 --- a/src/ResourceProvider/ResourceProviderClient.ts +++ b/src/ResourceProvider/ResourceProviderClient.ts @@ -1,6 +1,6 @@ import * as ViewModels from "../Contracts/ViewModels"; import { HttpStatusCodes } from "../Common/Constants"; -import { IResourceProviderClient } from "./IResourceProviderClient"; +import { IResourceProviderClient, IResourceProviderRequestOptions } from "./IResourceProviderClient"; import { OperationStatus } from "../Contracts/DataModels"; import { TokenProviderFactory } from "../TokenProviders/TokenProviderFactory"; import UrlUtility from "../Common/UrlUtility"; @@ -12,32 +12,74 @@ export class ResourceProviderClient implements IResourceProviderClient { this.httpClient = new HttpClient(); } - public async getAsync(url: string, apiVersion: string, queryString?: string): Promise { + public async getAsync( + url: string, + apiVersion: string, + queryString?: string, + requestOptions?: IResourceProviderRequestOptions + ): Promise { let uri = `${this.armEndpoint}${url}?api-version=${apiVersion}`; if (queryString) { uri += `&${queryString}`; } - return await this.httpClient.getAsync(uri); + return await this.httpClient.getAsync( + uri, + Object.assign({}, { skipResourceValidation: false }, requestOptions) + ); } - public async postAsync(url: string, apiVersion: string, body: any): Promise { + public async postAsync( + url: string, + apiVersion: string, + body: any, + requestOptions?: IResourceProviderRequestOptions + ): Promise { const fullUrl = UrlUtility.createUri(this.armEndpoint, url); - return await this.httpClient.postAsync(`${fullUrl}?api-version=${apiVersion}`, body); + return await this.httpClient.postAsync( + `${fullUrl}?api-version=${apiVersion}`, + body, + Object.assign({}, { skipResourceValidation: false }, requestOptions) + ); } - public async putAsync(url: string, apiVersion: string, body: any): Promise { + public async putAsync( + url: string, + apiVersion: string, + body: any, + requestOptions?: IResourceProviderRequestOptions + ): Promise { const fullUrl = UrlUtility.createUri(this.armEndpoint, url); - return await this.httpClient.putAsync(`${fullUrl}?api-version=${apiVersion}`, body); + return await this.httpClient.putAsync( + `${fullUrl}?api-version=${apiVersion}`, + body, + Object.assign({}, { skipResourceValidation: false }, requestOptions) + ); } - public async patchAsync(url: string, apiVersion: string, body: any): Promise { + public async patchAsync( + url: string, + apiVersion: string, + body: any, + requestOptions?: IResourceProviderRequestOptions + ): Promise { const fullUrl = UrlUtility.createUri(this.armEndpoint, url); - return await this.httpClient.patchAsync(`${fullUrl}?api-version=${apiVersion}`, body); + return await this.httpClient.patchAsync( + `${fullUrl}?api-version=${apiVersion}`, + body, + Object.assign({}, { skipResourceValidation: false }, requestOptions) + ); } - public async deleteAsync(url: string, apiVersion: string): Promise { + public async deleteAsync( + url: string, + apiVersion: string, + requestOptions?: IResourceProviderRequestOptions + ): Promise { const fullUrl = UrlUtility.createUri(this.armEndpoint, url); - return await this.httpClient.deleteAsync(`${fullUrl}?api-version=${apiVersion}`); + return await this.httpClient.deleteAsync( + `${fullUrl}?api-version=${apiVersion}`, + Object.assign({}, { skipResourceValidation: true }, requestOptions) + ); } } @@ -55,40 +97,44 @@ class HttpClient { this.tokenProvider = TokenProviderFactory.create(); } - public async getAsync(url: string): Promise { + public async getAsync(url: string, requestOptions: IResourceProviderRequestOptions): Promise { const args: RequestInit = { method: "GET" }; - const response = await this.httpRequest(new Request(url, args)); + const response = await this.httpRequest(new Request(url, args), requestOptions); return (await response.json()) as T; } - public async postAsync(url: string, body: any): Promise { + public async postAsync(url: string, body: any, requestOptions: IResourceProviderRequestOptions): Promise { body = typeof body !== "string" && body !== undefined ? JSON.stringify(body) : body; const args: RequestInit = { method: "POST", headers: { "Content-Type": "application/json" }, body }; - const response = await this.httpRequest(new Request(url, args)); + const response = await this.httpRequest(new Request(url, args), requestOptions); return await response.json(); } - public async putAsync(url: string, body: any): Promise { + public async putAsync(url: string, body: any, requestOptions: IResourceProviderRequestOptions): Promise { body = typeof body !== "string" && body !== undefined ? JSON.stringify(body) : body; const args: RequestInit = { method: "PUT", headers: { "Content-Type": "application/json" }, body }; - const response = await this.httpRequest(new Request(url, args)); + const response = await this.httpRequest(new Request(url, args), requestOptions); return (await response.json()) as T; } - public async patchAsync(url: string, body: any): Promise { + public async patchAsync(url: string, body: any, requestOptions: IResourceProviderRequestOptions): Promise { body = typeof body !== "string" && body !== undefined ? JSON.stringify(body) : body; const args: RequestInit = { method: "PATCH", headers: { "Content-Type": "application/json" }, body }; - const response = await this.httpRequest(new Request(url, args)); + const response = await this.httpRequest(new Request(url, args), requestOptions); return (await response.json()) as T; } - public async deleteAsync(url: string): Promise { + public async deleteAsync(url: string, requestOptions: IResourceProviderRequestOptions): Promise { const args: RequestInit = { method: "DELETE" }; - await this.httpRequest(new Request(url, args)); + await this.httpRequest(new Request(url, args), requestOptions); return null; } - public async httpRequest(request: RequestInfo, numRetries: number = 12): Promise { + public async httpRequest( + request: RequestInfo, + requestOptions: IResourceProviderRequestOptions, + numRetries: number = 12 + ): Promise { const authHeader = await this.tokenProvider.getAuthHeader(); authHeader && authHeader.forEach((value: string, header: string) => { @@ -99,7 +145,7 @@ class HttpClient { if (response.status === HttpStatusCodes.Accepted) { const operationStatusUrl: string = response.headers && response.headers.get(HttpClient.AZURE_ASYNC_OPERATION_HEADER); - const resource = await this.pollOperationAndGetResultAsync(request, operationStatusUrl); + const resource = await this.pollOperationAndGetResultAsync(request, operationStatusUrl, requestOptions); return new Response(resource && JSON.stringify(resource)); } @@ -112,7 +158,7 @@ class HttpClient { return new Promise((resolve: (value: Response) => void, reject: (error: any) => void) => { setTimeout(async () => { try { - const response = await this.httpRequest(request, numRetries - 1); + const response = await this.httpRequest(request, requestOptions, numRetries - 1); resolve(response); } catch (error) { reject(error); @@ -128,7 +174,7 @@ class HttpClient { response.headers && response.headers.get(HttpClient.AZURE_ASYNC_OPERATION_HEADER); if (operationStatusUrl) { - const resource = await this.pollOperationAndGetResultAsync(request, operationStatusUrl); + const resource = await this.pollOperationAndGetResultAsync(request, operationStatusUrl, requestOptions); return new Response(resource && JSON.stringify(resource)); } @@ -140,16 +186,17 @@ class HttpClient { private async pollOperationAndGetResultAsync( originalRequest: RequestInfo, - operationStatusUrl: string + operationStatusUrl: string, + requestOptions: IResourceProviderRequestOptions ): Promise { const getOperationResult = async (resolve: (value: T) => void, reject: (error: any) => void) => { - const operationStatus: OperationStatus = await this.getAsync(operationStatusUrl); + const operationStatus: OperationStatus = await this.getAsync(operationStatusUrl, requestOptions); if (!operationStatus) { return reject("Could not retrieve operation status"); } else if (operationStatus.status === HttpClient.SUCCEEDED_STATUS) { let result; - if ((originalRequest as Request).method !== "DELETE") { - result = await this.getAsync((originalRequest as Request).url); + if (requestOptions?.skipResourceValidation === false) { + result = await this.getAsync((originalRequest as Request).url, requestOptions); } return resolve(result); } else if (