From 7dddc2ade8d2dade79b5eb2726d1a288e31594de Mon Sep 17 00:00:00 2001 From: Jimmy Callin Date: Wed, 15 Mar 2023 16:32:26 +0000 Subject: [PATCH] chore: Migrate session methods to async await (#76) * chore: Migrate session methods to async await * fix: move response initialization to within try block --- source/session.ts | 167 +++++++++++++++++++--------------------------- 1 file changed, 69 insertions(+), 98 deletions(-) diff --git a/source/session.ts b/source/session.ts index dd111bc4..41937983 100644 --- a/source/session.ts +++ b/source/session.ts @@ -493,7 +493,7 @@ export class Session { * @param {string} options.decodeDatesAsIso - Return dates as ISO strings instead of moment objects * */ - call( + async call( operations: operation.Operation[], { abortController, @@ -503,21 +503,16 @@ export class Session { decodeDatesAsIso = false, }: CallOptions = {} ): Promise extends true ? T : T[]> { + await this.initializing; const url = `${this.serverUrl}${this.apiEndpoint}`; - // Delay call until session is initialized if initialization is in - // progress. - let request = new Promise((resolve) => { - if (this.initializing && !this.initialized) { - this.initializing.then(() => { - resolve(); - }); - } else { - resolve(); - } - }) - .then(() => - fetch(url, { + try { + // Delay call until session is initialized if initialization is in + // progress. + + let fetchResponse; + try { + fetchResponse = await fetch(url, { method: "post", credentials: "include", headers: { @@ -532,54 +527,45 @@ export class Session { } as HeadersInit, body: this.encodeOperations(operations), signal: abortController ? abortController.signal : signal, - }) - ) - .catch((reason) => { - logger.warn("Failed to perform request. ", reason); + }); + } catch (reason) { + if (reason instanceof Error) { + throw this.getErrorFromResponse({ + exception: "NetworkError", + content: reason.message, + }); + } + throw new Error("Unknown error"); + } + + const response = await fetchResponse.json(); + + if (response.exception) { + throw this.getErrorFromResponse(response); + } + + return this.decode(response, {}, decodeDatesAsIso); + } catch (reason) { + logger.warn("Failed to perform request. ", reason); + + if (reason instanceof Error) { if (reason.name === "AbortError") { - return Promise.resolve({ + throw this.getErrorFromResponse({ exception: "AbortError", content: reason.message, }); } - return Promise.resolve({ - exception: "NetworkError", - content: reason.message, - }); - }) - .then((response) => { - if ("json" in response) { - return (response.json && response.json()) || response; - } - return response; - }) - .then((data) => { - if (this.initialized) { - return this.decode(data, {}, decodeDatesAsIso); - } - return data; - }) - // Catch badly formatted responses - .catch((reason) => { logger.warn("Server reported error in unexpected format. ", reason); - return Promise.resolve({ + throw this.getErrorFromResponse({ exception: "MalformedResponseError", content: reason.message, error: reason, }); - }) - // Reject promise on API exception. - .then((response) => { - if (response.exception) { - return Promise.reject( - this.getErrorFromResponse(response as ResponseError) - ); - } - return Promise.resolve(response); - }); + } + } - return request; + throw new Error("Unknown error"); } /** @@ -716,17 +702,16 @@ export class Session { * @return {Promise} Promise which will be resolved with an object * containing action, data and metadata */ - query(expression: string, options: QueryOptions = {}) { + async query( + expression: string, + options: QueryOptions = {} + ) { logger.debug("Query", expression); - const queryOperation = operation.query(expression); - let request = this.call<[QueryResponse]>([queryOperation], options).then( - (responses) => { - const response = responses[0]; - return response; - } + const responses = await this.call<[QueryResponse]>( + [operation.query(expression)], + options ); - - return request; + return responses[0]; } /** @@ -746,7 +731,7 @@ export class Session { * @return {Promise} Promise which will be resolved with an object * containing data and metadata */ - search( + async search( { expression, entityType, @@ -764,22 +749,19 @@ export class Session { objectTypeIds, }); - const searchOperation = operation.search({ - expression, - entityType, - terms, - contextId, - objectTypeIds, - }); - let request = this.call<[SearchResponse]>( - [searchOperation], + const responses = await this.call<[SearchResponse]>( + [ + operation.search({ + expression, + entityType, + terms, + contextId, + objectTypeIds, + }), + ], options - ).then((responses) => { - const response = responses[0]; - return response; - }); - - return request; + ); + return responses[0]; } /** @@ -793,22 +775,18 @@ export class Session { * @param {object} options.decodeDatesAsIso - Decode dates as ISO strings instead of moment objects * @return {Promise} Promise which will be resolved with the response. */ - create( + async create( entityType: string, data: T, options: MutationOptions = {} ) { logger.debug("Create", entityType, data, options); - let request = this.call<[CreateResponse]>( + const responses = await this.call<[CreateResponse]>( [operation.create(entityType, data)], options - ).then((responses) => { - const response = responses[0]; - return response; - }); - - return request; + ); + return responses[0]; } /** @@ -823,7 +801,7 @@ export class Session { * @param {object} options.decodeDatesAsIso - Decode dates as ISO strings instead of moment objects * @return {Promise} Promise resolved with the response. */ - update( + async update( type: string, keys: string[], data: T, @@ -831,15 +809,11 @@ export class Session { ) { logger.debug("Update", type, keys, data, options); - const request = this.call<[UpdateResponse]>( + const responses = await this.call<[UpdateResponse]>( [operation.update(type, keys, data)], options - ).then((responses) => { - const response = responses[0]; - return response; - }); - - return request; + ); + return responses[0]; } /** @@ -853,18 +827,15 @@ export class Session { * @param {object} options.decodeDatesAsIso - Decode dates as ISO strings instead of moment objects * @return {Promise} Promise resolved with the response. */ - delete(type: string, keys: string[], options: MutationOptions = {}) { + async delete(type: string, keys: string[], options: MutationOptions = {}) { logger.debug("Delete", type, keys, options); - let request = this.call<[DeleteResponse]>( + const responses = await this.call<[DeleteResponse]>( [operation.delete(type, keys)], options - ).then((responses) => { - const response = responses[0]; - return response; - }); + ); - return request; + return responses[0]; } /**