Skip to content

Commit 90ad216

Browse files
committed
Add a helper method for infallible API requests
1 parent 3245fcd commit 90ad216

10 files changed

Lines changed: 115 additions & 67 deletions

File tree

ts/WoltLabSuite/Core/Api/Messages/MentionSuggestions.ts

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
*/
1010

1111
import { prepareRequest } from "WoltLabSuite/Core/Ajax/Backend";
12-
import { ApiResult, apiResultFromError, apiResultFromValue } from "../Result";
12+
import { fromInfallibleApiRequest } from "../Result";
1313

1414
type Item =
1515
| {
@@ -25,16 +25,11 @@ type Item =
2525
};
2626
type Response = Item[];
2727

28-
export async function mentionSuggestions(query: string): Promise<ApiResult<Response>> {
28+
export async function mentionSuggestions(query: string): Promise<Response> {
2929
const url = new URL(window.WSC_RPC_API_URL + "core/messages/mention-suggestions");
3030
url.searchParams.set("query", query);
3131

32-
let response: Response;
33-
try {
34-
response = (await prepareRequest(url).get().allowCaching().disableLoadingIndicator().fetchAsJson()) as Response;
35-
} catch (e) {
36-
return apiResultFromError(e);
37-
}
38-
39-
return apiResultFromValue(response);
32+
return fromInfallibleApiRequest<Response>(() => {
33+
return prepareRequest(url).get().allowCaching().disableLoadingIndicator().fetchAsJson();
34+
});
4035
}

ts/WoltLabSuite/Core/Api/Messages/RenderQuote.ts

Lines changed: 5 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
*/
1010

1111
import { prepareRequest } from "WoltLabSuite/Core/Ajax/Backend";
12-
import { ApiResult, apiResultFromError, apiResultFromValue } from "../Result";
12+
import { fromInfallibleApiRequest } from "../Result";
1313

1414
type Response = {
1515
objectID: number;
@@ -20,22 +20,13 @@ type Response = {
2020
rawMessage: string | null;
2121
};
2222

23-
export async function renderQuote(
24-
objectType: string,
25-
objectID: number,
26-
isFullQuote: boolean,
27-
): Promise<ApiResult<Response>> {
23+
export async function renderQuote(objectType: string, objectID: number, isFullQuote: boolean): Promise<Response> {
2824
const url = new URL(window.WSC_RPC_API_URL + "core/messages/render-quote");
2925
url.searchParams.set("objectType", objectType);
3026
url.searchParams.set("isFullQuote", String(isFullQuote));
3127
url.searchParams.set("objectID", objectID.toString());
3228

33-
let response: Response;
34-
try {
35-
response = (await prepareRequest(url).get().fetchAsJson()) as Response;
36-
} catch (e) {
37-
return apiResultFromError(e);
38-
}
39-
40-
return apiResultFromValue(response);
29+
return fromInfallibleApiRequest(() => {
30+
return prepareRequest(url).get().fetchAsJson();
31+
});
4132
}

ts/WoltLabSuite/Core/Api/Result.ts

Lines changed: 49 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,10 @@
1010
*/
1111

1212
import { StatusNotOk } from "../Ajax/Error";
13+
import { dialogFactory } from "../Component/Dialog";
1314
import { isPlainObject } from "../Core";
15+
import { getPhrase } from "../Language";
16+
import { escapeHTML } from "../StringUtil";
1417
import { ApiError } from "./Error";
1518

1619
export type ApiResult<T> =
@@ -58,7 +61,7 @@ export async function apiResultFromStatusNotOk(e: StatusNotOk): Promise<ApiResul
5861

5962
let json: unknown;
6063
try {
61-
json = await response.json();
64+
json = await response.clone().json();
6265
} catch {
6366
throw e;
6467
}
@@ -77,10 +80,55 @@ export async function apiResultFromStatusNotOk(e: StatusNotOk): Promise<ApiResul
7780
ok: false,
7881
error: apiError,
7982
unwrap() {
83+
showErrorDialog(apiError);
84+
8085
throw new Error("Trying to unwrap an erroneous result.", { cause: apiError });
8186
},
8287
};
8388
}
8489

8590
throw e;
8691
}
92+
93+
/**
94+
* Helper method for API requests that are expected to never fail. Infallible
95+
* requests are those that should only fail if there is an unexpected server
96+
* error or if the request was the result of a bug in the client.
97+
*/
98+
export async function fromInfallibleApiRequest<T = unknown>(request: () => Promise<unknown>): Promise<T> {
99+
try {
100+
return (await request()) as T;
101+
} catch (e) {
102+
const error = await apiResultFromError(e);
103+
return error.unwrap();
104+
}
105+
}
106+
107+
function showErrorDialog(apiError: ApiError): void {
108+
const code = escapeHTML(apiError.code);
109+
const type = escapeHTML(apiError.type);
110+
const message = apiError.message ? escapeHTML(apiError.message) : "(not set)";
111+
const param = apiError.param ? "<kbd>" + escapeHTML(apiError.param) + "</kbd>" : "(not set)";
112+
113+
const html = `
114+
<dl>
115+
<dt>Unexpected server error</dt>
116+
<dd><kbd>${type}</kbd></dd>
117+
</dl>
118+
<dl>
119+
<dt>Error code</dt>
120+
<dd><kbd>${code}</kbd></dd>
121+
</dl>
122+
<dl>
123+
<dt>Parameter</dt>
124+
<dd>${param}</dd>
125+
</dl>
126+
<dl>
127+
<dt>Message</dt>
128+
<dd>${message}</dd>
129+
</dl>
130+
`;
131+
132+
const dialog = dialogFactory().fromHtml(html).asAlert();
133+
dialog.show(getPhrase("wcf.global.error.title"));
134+
}

ts/WoltLabSuite/Core/Component/Ckeditor/Mention.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ async function getPossibleMentions(query: string): Promise<Mention[]> {
2525
return [];
2626
}
2727

28-
return (await mentionSuggestions(query)).unwrap().map((item) => {
28+
return (await mentionSuggestions(query)).map((item) => {
2929
if (item.type === "user") {
3030
return {
3131
id: `@${item.username}`,

ts/WoltLabSuite/Core/Component/Quote/Storage.ts

Lines changed: 2 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -60,12 +60,7 @@ export async function saveQuote(
6060
.dispatch()) as LegacyQuoteData;
6161
quote = result.renderedQuote;
6262
} else {
63-
const result = await renderQuote(objectType, objectId, false);
64-
if (!result.ok) {
65-
throw new Error("Error fetching quote data");
66-
}
67-
68-
quote = result.value;
63+
quote = await renderQuote(objectType, objectId, false);
6964
}
7065

7166
const uuid = storeQuote(objectType, quote, {
@@ -94,12 +89,7 @@ export async function saveFullQuote(
9489
const result = (await dboAction("saveFullQuote", className).objectIds([objectId]).dispatch()) as LegacyQuoteData;
9590
message = result.renderedQuote;
9691
} else {
97-
const result = await renderQuote(objectType, objectId, true);
98-
if (!result.ok) {
99-
throw new Error("Error fetching quote data");
100-
}
101-
102-
message = result.value;
92+
message = await renderQuote(objectType, objectId, true);
10393
}
10494

10595
const uuid = storeQuote(objectType, message, message);

wcfsetup/install/files/js/WoltLabSuite/Core/Api/Messages/MentionSuggestions.js

Lines changed: 3 additions & 8 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

wcfsetup/install/files/js/WoltLabSuite/Core/Api/Messages/RenderQuote.js

Lines changed: 3 additions & 8 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

wcfsetup/install/files/js/WoltLabSuite/Core/Api/Result.js

Lines changed: 44 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

wcfsetup/install/files/js/WoltLabSuite/Core/Component/Ckeditor/Mention.js

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

wcfsetup/install/files/js/WoltLabSuite/Core/Component/Quote/Storage.js

Lines changed: 2 additions & 10 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)