Add simple error handling for when restaurant data cannot be fetched

This commit is contained in:
Mikko Ahlroth 2020-01-02 21:27:45 +02:00
parent 400821bf82
commit 1ed1913197
5 changed files with 81 additions and 27 deletions

View file

@ -1,7 +1,7 @@
import { HTML_ID, RESTAURANTS, DAY_NAMES } from './config.js';
import { getAllMenus } from './sodexo-api.js';
import { getAllMenus, SodexoAPIError } from './sodexo-api.js';
import { parseBlob } from './parser.js';
import { renderMenu } from './view.js';
import { renderMenu, renderError } from './view.js';
import { el } from './dom.js';
import { VERSION, SOURCE } from './version.js';
@ -14,7 +14,13 @@ async function init() {
rootEl.innerText = 'Loading…';
const menus = await getAllMenus(RESTAURANTS);
const parsedMenus = menus.map((m, idx) => parseBlob(m, RESTAURANTS[idx]));
const parsedMenus = menus.map((m, idx) => {
if (!(m instanceof SodexoAPIError)) {
return parseBlob(m, RESTAURANTS[idx]);
} else {
return m;
}
});
rootEl.innerText = '';
@ -25,8 +31,11 @@ async function init() {
);
}
for (const menu of parsedMenus) {
const [heading, ...elems] = renderMenu(menu);
for (const data of parsedMenus) {
if (data instanceof SodexoAPIError) {
rootEl.appendChild(renderError(data));
} else {
const [heading, ...elems] = renderMenu(data);
rootEl.appendChild(heading);
for (const day of DAY_NAMES) {
@ -45,6 +54,7 @@ async function init() {
}
for (const elem of elems) { rootEl.appendChild(elem); }
}
}
const versionEl = el('div', { classes: ['version'], text: `Versio ${VERSION}. ` });
versionEl.appendChild(

View file

@ -3,7 +3,14 @@ import { ServerBlob } from './types.js';
const API_URL = new URL('https://www.sodexo.fi/ruokalistat/output/weekly_json/');
export class SodexoAPIError extends Error { }
export class SodexoAPIError extends Error {
public restaurantId: RestaurantId;
constructor(message: string, restaurantId: RestaurantId) {
super(message);
this.restaurantId = restaurantId;
}
}
export async function getMenu(restaurantId: RestaurantId): Promise<ServerBlob> {
const url = new URL(String(restaurantId), API_URL);
@ -13,15 +20,28 @@ export async function getMenu(restaurantId: RestaurantId): Promise<ServerBlob> {
return await resp.json();
} else {
console.error(resp);
throw new SodexoAPIError(`Got invalid response: ${resp.status}.`);
throw new SodexoAPIError(
`Got invalid response: ${resp.status} ${resp.statusText}.`,
restaurantId
);
}
}
export async function getAllMenus(restaurants: readonly RestaurantId[]): Promise<ServerBlob[]> {
const promises = [];
export type MenuResult = ServerBlob | SodexoAPIError;
export async function getAllMenus(restaurants: readonly RestaurantId[]): Promise<MenuResult[]> {
const promises: Promise<MenuResult>[] = [];
for (const restaurant of restaurants) {
promises.push(getMenu(restaurant));
promises.push(
new Promise(async resolve => {
try {
resolve(await getMenu(restaurant));
} catch (e) {
resolve(e);
}
})
);
}
return await Promise.all(promises);

View file

@ -1,3 +1,3 @@
export const VERSION = '1.0.0';
export const VERSION = '1.0.1';
export const SOURCE = 'https://gitlab.com/Nicd/sodexo-menu';

View file

@ -1,5 +1,7 @@
import { MenuData, Course } from './types.js';
import { el } from './dom.js';
import { SodexoAPIError } from './sodexo-api.js';
import { RESTAURANTS } from './config.js';
function renderCourse(course: Course): HTMLLIElement {
const li = el('li');
@ -44,3 +46,13 @@ export function renderMenu(menu: MenuData): HTMLElement[] {
return [heading, ...dayElements, metaElem];
}
export function renderError(data: SodexoAPIError): HTMLElement {
const errorDiv = el('div', { classes: ['error'] });
errorDiv.appendChild(
el('h2', { text: `Unable to fetch menu for "${RESTAURANTS[data.restaurantId]}":` })
);
errorDiv.appendChild(el('p', { text: data.message }));
errorDiv.appendChild(el('p', { classes: ['stack'], text: data.stack }));
return errorDiv;
}

View file

@ -39,7 +39,7 @@ main {
gap: 10px;
}
h2, .meta {
h2, .meta, .error {
grid-column: span 5;
}
@ -118,3 +118,15 @@ p.course-price {
.version {
font-size: 75%;
}
.error h2 {
margin-bottom: 0;
}
.error p {
margin: 5px 0;
}
.error .stack {
white-space: pre-wrap;
}