Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add non-success response logging to FetchClient #406

Merged
merged 7 commits into from
Aug 8, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 36 additions & 2 deletions packages/libs/http-utils/src/FetchClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,19 +37,49 @@ export interface FetchApiOptions {
init?: RequestInit;
/** Implementation of `fetch` function. Defaults to `window.fetch`. */
fetchApi?: Window['fetch'];
/**
* Callback that can be used for reporting errors. A Promise rejection will
* still occur.
*/
onNonSuccessResponse?: (error: Error) => void;
}

class FetchClientError extends Error {
name = 'FetchClientError';
}

export abstract class FetchClient {
/** Default callback used, if none is specified to constructor. */
private static onNonSuccessResponse: FetchApiOptions['onNonSuccessResponse'];

protected readonly baseUrl: string;
protected readonly init: RequestInit;
protected readonly fetchApi: Window['fetch'];
protected readonly onNonSuccessResponse: FetchApiOptions['onNonSuccessResponse'];
// Subclasses can set this to false to disable including a traceparent header with all requests.
protected readonly includeTraceidHeader: boolean = true;

constructor(options: FetchApiOptions) {
this.baseUrl = options.baseUrl;
this.init = options.init ?? {};
this.fetchApi = options.fetchApi ?? window.fetch;
this.onNonSuccessResponse =
options.onNonSuccessResponse ?? FetchClient.onNonSuccessResponse;
}

/**
* Set a default callback for all instances. Should only be called once.
*/
public static setOnNonSuccessResponse(
callback: FetchApiOptions['onNonSuccessResponse']
) {
if (this.onNonSuccessResponse) {
console.warn(
'FetchClient.setOnNonSuccessResponse() should only be called once.'
);
return;
}
this.onNonSuccessResponse = callback;
}

protected async fetch<T>(apiRequest: ApiRequest<T>): Promise<T> {
Expand All @@ -74,9 +104,13 @@ export abstract class FetchClient {

return await transformResponse(responseBody);
}
throw new Error(
`${response.status} ${response.statusText}${'\n'}${await response.text()}`
const fetchError = new FetchClientError(
`${request.method.toUpperCase()} ${request.url}: ${response.status} ${
response.statusText
}${'\n'}${await response.text()}`
);
this.onNonSuccessResponse?.(fetchError);
throw fetchError;
}
}

Expand Down
6 changes: 6 additions & 0 deletions packages/libs/web-common/src/bootstrap.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import { debounce, identity, uniq, flow } from 'lodash';

// TODO Remove auth_tkt from url before proceeding

import { FetchClient } from '@veupathdb/http-utils';
import { initialize as initializeWdk_ } from '@veupathdb/wdk-client/lib/Core/main';
import * as WdkComponents from '@veupathdb/wdk-client/lib/Components';
import * as WdkControllers from '@veupathdb/wdk-client/lib/Controllers';
Expand Down Expand Up @@ -94,6 +95,11 @@ export function initialize(options = {}) {

context.store.dispatch(loadSiteConfig(siteConfig));

// Add non-success response handler for FetchClient instances
FetchClient.setOnNonSuccessResponse((error) => {
context.wdkService.submitError(error);
});

return context;
}

Expand Down
196 changes: 0 additions & 196 deletions packages/libs/web-common/src/util/api.ts

This file was deleted.