import {Rivendell} from './Rivendell'; export type Method = 'POST' | 'PUT' | 'PATCH' | 'GET' | 'DELETE'; /** * Low level http handler for interacting with the Moria api. */ export namespace MoriaApi { interface ApiResponse { response: Response; body: T; } export class ApiError extends Error { constructor(message: string, public responseText: string, public response?: Response) { super(message); } } export async function get(shard: Rivendell.Shard, uri: string): Promise> { return request(shard, 'GET', uri); } export async function post(shard: Rivendell.Shard, uri: string, body: any): Promise> { return request(shard, 'POST', uri, body); } export async function put(shard: Rivendell.Shard, uri: string, body: any): Promise> { return request(shard, 'PUT', uri, body); } export async function request( shard: Rivendell.Shard, method: Method, uri: string, body?: any ): Promise> { const url = `${shard.url}/${uri}`; const requestPayload: RequestInit = { method }; requestPayload.headers = { 'Authorization': `Bearer ${await Rivendell.jwt(shard.id)}` }; if (body && method !== 'GET') { // @ts-ignore requestPayload.headers['content-type'] = 'application/json'; requestPayload.body = JSON.stringify(body); } const response = await fetch(url, requestPayload); const responseText = await response.text(); if (response.status < 200 || response.status >= 300) { const errorMsg = `Received a ${response.status} from OCP: ${getErrorMessage(response.status)}`; throw new ApiError(errorMsg, responseText, response); } return { response, body: responseText ? JSON.parse(responseText) : '' }; } function getErrorMessage(code: number): string { switch (code) { case 400: return 'Bad request.'; case 403: return 'Access denied.'; case 404: return 'Not found.'; case 500: return 'Internal service error.'; case 502: return 'Bad gateway'; case 503: return 'Service unavailable. Please try again.'; case 504: return 'Request timed out. Please try again.'; default: return 'Unhandled error.'; } } }