@samchon/openapi
Version:
OpenAPI definitions and converters for 'typia' and 'nestia'.
102 lines (92 loc) • 5.95 kB
JavaScript
import { HttpError } from "./HttpError.mjs";
var HttpMigrateRouteFetcher;
(function(HttpMigrateRouteFetcher) {
HttpMigrateRouteFetcher.execute = async props => {
const result = await _Propagate("request", props);
props.route.success?.media;
if (result.status !== 200 && result.status !== 201) throw new HttpError(props.route.method.toUpperCase(), props.route.path, result.status, result.headers, result.body);
return result.body;
};
HttpMigrateRouteFetcher.propagate = props => _Propagate("propagate", props);
})(HttpMigrateRouteFetcher || (HttpMigrateRouteFetcher = {}));
const _Propagate = async (from, props) => {
const error = message => new Error(`Error on MigrateRouteFetcher.${from}(): ${message}`);
if (Array.isArray(props.parameters)) {
if (props.route.parameters.length !== props.parameters.length) throw error(`number of parameters is not matched.`);
} else if (props.route.parameters.every((p => props.parameters[p.key] !== undefined)) === false) throw error(`number of parameters is not matched.`);
if (!!props.route.query !== !!props.query) throw error(`query is not matched.`); else if (!!props.route.body !== (props.body !== undefined)) throw error(`body is not matched.`);
const headers = {
...props.connection.headers ?? {},
...props.route.body?.type && props.route.body.type !== "multipart/form-data" ? {
"Content-Type": props.route.body.type
} : {}
};
const init = {
...props.connection.options ?? {},
method: props.route.method.toUpperCase(),
headers: (() => {
const output = [];
for (const [key, value] of Object.entries(headers)) if (value === undefined) continue; else if (Array.isArray(value)) for (const v of value) output.push([ key, String(v) ]); else output.push([ key, String(value) ]);
return output;
})()
};
if (props.body !== undefined) init.body = props.route.body?.type === "application/x-www-form-urlencoded" ? requestQueryBody(props.body) : props.route.body?.type === "multipart/form-data" ? requestFormDataBody(props.body) : props.route.body?.type === "application/json" ? JSON.stringify(props.body) : props.body;
const resolvedPath = props.connection.host.endsWith("/") === false && props.route.emendedPath.startsWith("/") === false ? `/${getPath(props)}` : getPath(props);
const url = new URL(`${props.connection.host}${resolvedPath}`);
const response = await (props.connection.fetch ?? fetch)(url, init);
const status = response.status;
const out = body => ({
status,
headers: responseHeaders(response.headers),
body
});
if (status === 200 || status === 201) {
if (props.route.method.toUpperCase() === "HEAD") return out(undefined); else if (props.route.success === null || props.route.success.type === "text/plain") return out(await response.text()); else if (props.route.success.type === "application/json") {
const text = await response.text();
return out(text.length ? JSON.parse(text) : undefined);
} else if (props.route.success.type === "application/x-www-form-urlencoded") return out(new URLSearchParams(await response.text())); else if (props.route.success.type === "multipart/form-data") return out(await response.formData());
throw error("Unsupported response body type.");
} else {
const type = (response.headers.get("content-type") ?? response.headers.get("Content-Type") ?? "").split(";")[0].trim();
if (type === "" || type.startsWith("text/")) return out(await response.text()); else if (type === "application/json") return out(await response.json()); else if (type === "application/x-www-form-urlencoded") return out(new URLSearchParams(await response.text())); else if (type === "multipart/form-data") return out(await response.formData()); else if (type === "application/octet-stream") return out(await response.blob());
return out(await response.text());
}
};
const getPath = props => {
let path = props.route.emendedPath;
props.route.parameters.forEach(((p, i) => {
path = path.replace(`:${p.key}`, encodeURIComponent(String((Array.isArray(props.parameters) ? props.parameters[i] : props.parameters[p.key]) ?? "null")));
}));
if (props.route.query) path += getQueryPath(props.query ?? {});
return path;
};
const getQueryPath = query => {
const variables = new URLSearchParams;
for (const [key, value] of Object.entries(query)) if (undefined === value) continue; else if (Array.isArray(value)) value.forEach((elem => variables.append(key, String(elem)))); else variables.set(key, String(value));
return 0 === variables.size ? "" : `?${variables.toString()}`;
};
const requestQueryBody = input => {
const q = new URLSearchParams;
for (const [key, value] of Object.entries(input)) if (value === undefined) continue; else if (Array.isArray(value)) value.forEach((elem => q.append(key, String(elem)))); else q.set(key, String(value));
return q;
};
const requestFormDataBody = input => {
const encoded = new FormData;
const append = key => value => {
if (value === undefined) return; else if (typeof File === "function" && value instanceof File) encoded.append(key, value, value.name); else encoded.append(key, value);
};
for (const [key, value] of Object.entries(input)) if (Array.isArray(value)) value.map(append(key)); else append(key)(value);
return encoded;
};
const responseHeaders = headers => {
const output = {};
headers.forEach(((value, key) => {
if (key === "set-cookie") {
output[key] ?? (output[key] = []);
output[key].push(...value.split(";").map((str => str.trim())));
} else output[key] = value;
}));
return output;
};
export { HttpMigrateRouteFetcher };
//# sourceMappingURL=HttpMigrateRouteFetcher.mjs.map