@nodescript/stdlib
Version:
Standard Node Definitions
117 lines (116 loc) • 3.79 kB
JavaScript
import { determineRequestBody, FetchResponseType, headersToObject, HttpRequestFailed, mergeUrlQuery, readResponse, } from '../lib/web.js';
export const module = {
version: '1.6.4',
moduleName: 'Web / Fetch',
description: `
Sends an HTTP request using natively available Fetch API.
Note: when sent from the browser, the request is subject to Cross-Origin Resource Sharing (CORS) policy,
along with other limitations. Use HTTP Request node for a general purpose HTTP client.
`,
keywords: ['http', 'request'],
params: {
method: {
schema: {
type: 'string',
enum: ['GET', 'POST', 'PUT', 'DELETE', 'PATCH'],
default: 'GET',
},
},
url: {
schema: { type: 'string' },
},
query: {
schema: {
type: 'object',
properties: {},
additionalProperties: { type: 'string', optional: true },
},
advanced: true,
},
headers: {
schema: {
type: 'object',
properties: {},
additionalProperties: { type: 'string', optional: true },
},
advanced: true,
},
body: {
schema: { type: 'any' },
hideValue: true,
advanced: true,
},
throw: {
schema: { type: 'boolean', default: true },
advanced: true,
},
responseType: {
schema: {
type: 'string',
enum: Object.values(FetchResponseType),
default: FetchResponseType.AUTO,
},
advanced: true,
},
},
result: {
async: true,
schema: {
type: 'object',
properties: {
status: { type: 'number' },
url: { type: 'string' },
headers: {
type: 'object',
additionalProperties: { type: 'any' },
},
body: { type: 'any' },
}
},
},
cacheMode: 'always',
evalMode: 'manual',
};
export const compute = async (params, ctx) => {
const { method, url, query, headers, body, responseType = FetchResponseType.AUTO, } = params;
if (!url) {
// Do not send requests to self by default
return undefined;
}
if (!/^https?:\/\//.test(url)) {
throw new Error('URL must start with http:// or https://');
}
const actualUrl = mergeUrlQuery(url, query);
const actualHeaders = prepareHeaders(headers);
const [actualBody, bodyContentType] = determineRequestBody(method, body);
if (bodyContentType && !actualHeaders.has('Content-Type')) {
actualHeaders.set('Content-Type', bodyContentType);
}
const res = await fetch(actualUrl, {
method,
headers: actualHeaders,
body: actualBody,
});
if (params.throw && !res.ok) {
const responseBody = await res.text();
const details = ctx.lib.parseJson(responseBody) ?? { response: responseBody };
throw new HttpRequestFailed(res.status, method, url, details);
}
const resContentType = res.headers.get('content-type') ?? 'text/plain';
return {
url: res.url,
status: res.status,
headers: headersToObject(res.headers),
body: await readResponse(res, responseType, resContentType),
};
};
function prepareHeaders(headers) {
const entries = {};
for (const [key, value] of Object.entries(headers)) {
if (value === undefined) {
continue;
}
entries[key] = String(value);
}
return new Headers(entries);
}