Skip to content

Commit

Permalink
Throws more useful error when fetch fails (#2921)
Browse files Browse the repository at this point in the history
  • Loading branch information
Pessimistress authored Apr 4, 2024
1 parent 46d7f30 commit 51af025
Show file tree
Hide file tree
Showing 9 changed files with 69 additions and 11 deletions.
1 change: 1 addition & 0 deletions modules/core/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ export type {

// FILE READING AND WRITING
export {fetchFile} from './lib/fetch/fetch-file';
export {FetchError} from './lib/fetch/fetch-error';

export {readArrayBuffer} from './lib/fetch/read-array-buffer';
// export {readFileSync} from './lib/fetch/read-file';
Expand Down
2 changes: 2 additions & 0 deletions modules/core/src/lib/fetch/fetch-error-message.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,12 @@
// SPDX-License-Identifier: MIT
// Copyright (c) vis.gl contributors

// TODO - duplicates response-utils code
export function getErrorMessageFromResponseSync(response: Response): string {
return `Failed to fetch resource ${response.url}(${response.status}): ${response.statusText} `;
}

// TODO - duplicates response-utils code
export async function getErrorMessageFromResponse(response: Response): Promise<string> {
let message = `Failed to fetch resource ${response.url} (${response.status}): `;
try {
Expand Down
18 changes: 18 additions & 0 deletions modules/core/src/lib/fetch/fetch-error.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
// loaders.gl
// SPDX-License-Identifier: MIT
// Copyright (c) vis.gl contributors

export class FetchError extends Error {
constructor(message: string, info: {url: string; reason: string; response?: Response}) {
super(message);
this.reason = info.reason;
this.url = info.url;
this.response = info.response;
}
/** A best effort reason for why the fetch failed */
reason: string;
/** The URL that failed to load. Empty string if not available. */
url: string;
/** The Response object, if any. */
response?: Response;
}
1 change: 1 addition & 0 deletions modules/core/src/lib/fetch/fetch-file.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

import {resolvePath} from '@loaders.gl/loader-utils';
import {makeResponse} from '../utils/response-utils';
// import {FetchError} from './fetch-error';

export function isNodePath(url: string): boolean {
return !isRequestURL(url) && !isDataURL(url);
Expand Down
30 changes: 19 additions & 11 deletions modules/core/src/lib/utils/response-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@
// Copyright (c) vis.gl contributors

import {isResponse} from '../../javascript-utils/is-type';
import {FetchError} from '../fetch/fetch-error';
import {getResourceContentLength, getResourceUrl, getResourceMIMEType} from './resource-utils';
import {shortenUrlForDisplay} from './url-utils';

/**
* Returns a Response object
Expand Down Expand Up @@ -58,8 +60,8 @@ export async function makeResponse(resource: unknown): Promise<Response> {
*/
export async function checkResponse(response: Response): Promise<void> {
if (!response.ok) {
const message = await getResponseError(response);
throw new Error(message);
const error = await getResponseError(response);
throw error;
}
}

Expand All @@ -77,20 +79,26 @@ export function checkResponseSync(response: Response): void {

// HELPERS

async function getResponseError(response: Response): Promise<string> {
let message = `Failed to fetch resource ${response.url} (${response.status}): `;
async function getResponseError(response: Response): Promise<Error> {
const shortUrl = shortenUrlForDisplay(response.url);
let message = `Failed to fetch resource (${response.status}) ${response.statusText}: ${shortUrl}`;
message = message.length > 100 ? `${message.slice(0, 100)}...` : message;

const info = {
reason: response.statusText,
url: response.url,
response
};

try {
const contentType = response.headers.get('Content-Type');
let text = response.statusText;
if (contentType?.includes('application/json')) {
text += ` ${await response.text()}`;
}
message += text;
message = message.length > 60 ? `${message.slice(0, 60)}...` : message;
info.reason = contentType?.includes('application/json')
? await response.json()
: response.text();
} catch (error) {
// eslint forbids return in a finally statement, so we just catch here
}
return message;
return new FetchError(message, info);
}

async function getInitialDataUrl(
Expand Down
9 changes: 9 additions & 0 deletions modules/core/src/lib/utils/url-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,12 @@ export function extractQueryString(url): string {
export function stripQueryString(url): string {
return url.replace(QUERY_STRING_PATTERN, '');
}

export function shortenUrlForDisplay(url: string): string {
if (url.length < 50) {
return url;
}
const urlEnd = url.slice(url.length - 15);
const urlStart = url.substr(0, 32);
return `${urlStart}...${urlEnd}`;
}
1 change: 1 addition & 0 deletions modules/core/test/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import './iterators/make-stream.spec';
import './lib/utils/mime-type-utils.spec';
import './lib/utils/resource-utils.spec';
import './lib/utils/response-utils.spec';
import './lib/utils/url-utils.spec';

import './lib/loader-utils/loggers.spec';
import './lib/loader-utils/option-utils.spec';
Expand Down
3 changes: 3 additions & 0 deletions modules/core/test/lib/utils/response-utils.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,9 @@ test('checkResponseSync', (t) => {

test('checkResponse', async (t) => {
const response = new Response('{message: "server died"}', {status: 500});
Object.defineProperty(response, 'url', {
value: 'https://some.url/not/even/very/long'
});
t.equal(response.ok, false, 'Check reponse.ok');
t.rejects(() => checkResponse(response), /500/, 'Check reponse throws');
// t.throws()
Expand Down
15 changes: 15 additions & 0 deletions modules/core/test/lib/utils/url-utils.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// loaders.gl
// SPDX-License-Identifier: MIT
// Copyright (c) vis.gl contributors

import test from 'tape-promise/tape';
import {shortenUrlForDisplay} from '@loaders.gl/core/lib/utils/url-utils';

test('shortenUrlForDisplay', async (t) => {
const longUrl =
'http://www.longsitename.com/path1/path2/path3/longpath/longresourcename.extension';
const shortUrl = shortenUrlForDisplay(longUrl);

t.equal(shortUrl, 'http://www.longsitename.com/path...ename.extension');
t.end();
});

0 comments on commit 51af025

Please sign in to comment.