UNPKG

@opra/client

Version:

Opra Client package

186 lines (185 loc) 6.05 kB
import { updateErrorMessage } from '@jsopen/objects'; import { ApiDocument, ApiDocumentFactory, OpraSchema, } from '@opra/common'; import { kBackend } from './constants.js'; import { HttpBackend } from './http-backend.js'; import { HttpBundleObservable } from './http-bundle-observable.js'; import { HttpRequestObservable } from './http-request-observable.js'; const SPLIT_BACKSLASH_PATTERN = /^(\/*)(.+)/; /** * Base class for OPRA HTTP clients. * * @class OpraClientBase * @abstract */ export class HttpClientBase { /** * Creates a new instance of HttpClientBase. * * @param backend The backend instance to use for requests. * @protected */ constructor(backend) { Object.defineProperty(this, kBackend, { enumerable: false, value: backend, }); } /** * Gets the base service URL. */ get serviceUrl() { return this[kBackend].serviceUrl; } /** * Fetches the API document from the service. * * @param options Fetch options. * @returns A promise that resolves to an ApiDocument. * @throws {@link Error} if there is an issue fetching or parsing the document. */ async fetchDocument(options) { const documentMap = {}; const getDocument = async (documentId) => { const req = this.request('$schema', { headers: new Headers({ accept: 'application/json' }), }); if (documentId) req.param('id', documentId); const body = await req.getBody().catch(e => { updateErrorMessage(e, 'Error fetching api schema from url (' + this.serviceUrl + ').\n' + e.message); throw e; }); if (body.references) { const oldReferences = body.references; body.references = {}; for (const [ns, obj] of Object.entries(oldReferences)) { if (documentMap[obj.id] === null) throw new Error('Circular reference detected'); documentMap[obj.id] = null; const x = await getDocument(obj.id); body.references[ns] = documentMap[obj.id] = x; } } return body; }; const body = await getDocument(options?.documentId); return await ApiDocumentFactory.createDocument(body).catch(e => { updateErrorMessage(e, 'Error loading api document.\n' + e.message); throw e; }); } /** * Creates a new {@link HttpRequestObservable} for a specific path. * * @param path The path of the request. * @param options Request options. * @returns A new HttpRequestObservable instance. */ request(path, options) { /* Remove leading backslashes */ path = SPLIT_BACKSLASH_PATTERN.exec(path)?.[2] || ''; const observable = new HttpRequestObservable(this[kBackend], { ...options, method: options?.method || 'GET', url: new URL(path, this.serviceUrl), }); if (options?.params) observable.param(options.params); return observable; } /** * Sends a DELETE request. * * @param path The path of the request. * @param options Request options. * @returns A new HttpRequestObservable instance. */ delete(path, options) { return this.request(path, { ...options, method: 'DELETE', }); } /** * Sends a GET request. * * @param path The path of the request. * @param options Request options. * @returns A new HttpRequestObservable instance. */ get(path, options) { return this.request(path, { ...options, method: 'GET', }); } /** * Sends a PATCH request. * * @param path The path of the request. * @param requestBody The request body. * @param options Request options. * @returns A new HttpRequestObservable instance. */ patch(path, requestBody, options) { return this.request(path, { ...options, method: 'PATCH', body: requestBody, }); } /** * Sends a POST request. * * @param path The path of the request. * @param requestBody The request body. * @param options Request options. * @returns A new HttpRequestObservable instance. */ post(path, requestBody, options) { return this.request(path, { ...options, method: 'POST', body: requestBody, }); } /** * Sends a PUT request. * * @param path The path of the request. * @param requestBody The request body. * @param options Request options. * @returns A new HttpRequestObservable instance. */ put(path, requestBody, options) { return this.request(path, { ...options, method: 'PUT', body: requestBody, }); } /** * Bundles multiple requests into a single multipart HTTP request and * distributes the parsed sub-responses back to callers. * * @param requests The list of requests to bundle. * @returns A {@link HttpBundleObservable} that emits an ordered array of {@link HttpResponse}. */ bundle(requests) { return new HttpBundleObservable(this[kBackend], requests); } /** * Executes a transaction composed of multiple HTTP requests. * * @param {HttpRequestObservable<any>[]} requests - An array of HTTP request observables that are part of the transaction. * @return {HttpBundleObservable} A new observable that represents the bundled transaction. */ transaction(requests) { return new HttpBundleObservable(this[kBackend], requests).param({ transaction: true, }); } }