shelving
Version:
Toolkit for using data in JavaScript.
45 lines (44 loc) • 2.3 kB
JavaScript
import { MethodNotAllowedError, NotFoundError } from "../../error/RequestError.js";
import { ValueError } from "../../error/ValueError.js";
import { requireDictionary } from "../../util/dictionary.js";
import { getResponse, isRequestMethod, parseRequestBody } from "../../util/http.js";
import { isPlainObject } from "../../util/object.js";
import { matchURLPrefix } from "../../util/url.js";
export function handleEndpoints(base, handlers, request, context, caller = handleEndpoints) {
const { url, method } = request;
if (!isRequestMethod(method))
throw new MethodNotAllowedError("Unsupported request method", { received: method, caller });
const { pathname: requestPath, searchParams } = new URL(url, base);
const targetPath = matchURLPrefix(url, base);
if (!targetPath)
throw new NotFoundError("No matching base path", { received: requestPath, caller });
for (const handler of handlers) {
const pathParams = handler.endpoint.match(method, targetPath, caller);
if (!pathParams)
continue;
const params = searchParams.size ? { ...requireDictionary(searchParams), ...pathParams } : pathParams;
return _handleEndpoint(handler, params, request, context, handleEndpoints);
}
throw new NotFoundError("No matching endpoint", { received: targetPath, caller });
}
/**
* Validate and invoke an endpoint callback after the routing layer has already matched URL params.
*/
async function _handleEndpoint({ endpoint, callback },
/** Params we already matched/parsed from the URL. */
params, request, context, caller) {
const content = await parseRequestBody(request, caller);
const unsafePayload = content === undefined ? params : isPlainObject(content) ? { ...content, ...params } : content;
const payload = endpoint.payload.validate(unsafePayload);
const unsafeResult = await callback(payload, request, context);
if (unsafeResult instanceof Response)
return unsafeResult;
try {
return getResponse(endpoint.result.validate(unsafeResult));
}
catch (thrown) {
if (typeof thrown === "string")
throw new ValueError(`Invalid result for ${endpoint.toString()}:\n${thrown}`, { endpoint, callback, cause: thrown, caller });
throw thrown;
}
}