![Oracle Drags Its Feet in the JavaScript Trademark Dispute](https://cdn.sanity.io/images/cgdhsj6q/production/919c3b22c24f93884c548d60cbb338e819ff2435-1024x1024.webp?w=400&fit=max&auto=format)
Security News
Oracle Drags Its Feet in the JavaScript Trademark Dispute
Oracle seeks to dismiss fraud claims in the JavaScript trademark dispute, delaying the case and avoiding questions about its right to the name.
@data-eden/network
Advanced tools
fetch
with the same API as window.fetch
, compatible with anything that understands fetch
.POST
requestsexport type Middleware = (request: Request, next: (request: Request) => Promise<Response>) : Promise<Response>;
export interface BuildFetchOptions {
// Whether to force earlier built fetches to error making the most recent //
// invokation the authoritive fetch. You will typically only want to set this to
// false for testing. Defaults to true.
disablePrior?: boolean;
// What message to throw if a user tries to invoke a disabled fetch. Useful
// to help users know where to import fetch from rather than build it //
// themselves.
disableMessage?: string;
}
export function buildFetch(
middlewares: Middleware[],
options?: BuildFetchOptions
): typeof fetch;
type Fetch = typeof fetch;
async function noopMiddleware(
request: Request,
next: (request: Request) => Promise<Response>
): Promise<Response> {
return next(request);
}
async function csrfMiddleware(
request: Request,
next: (request: Request) => Promise<Response>
): Promise<Response> {
request.headers.set('X-CSRF', 'a totally legit request');
return next(request);
}
// e.g. fetch('https://example.com?foo=1&bar=two
async function queryTunneling(
request: Request,
next: (request: Request) => Promise<Response>
): Promise<Response> {
if (request.url.length <= MaxURLLength) {
// no tunneling needed
return next(request);
}
let url = new URL(request.url);
request.headers.set('X-HTTP-Method-Override', request.method);
let tunneledRequest = new Request(
`${url.protocol}//${url.hostname}${url.pathname}`,
{
method: 'POST',
headers: request.headers,
body: url.searchParams,
}
);
return next(tunneledRequest);
}
async function analyticsMiddleware(
request: Request,
next: (request: Request) => Promise<Response>
): Promise<Response> {
let response = await next(request);
let requestHeaders = [...request.headers.keys()];
let responseHeaders = [...response.headers.keys()];
let status = response.status;
let contentType = response.headers.get('content-type'); // Headers.get is case-insensitive
let analyticsEntries = [];
if (/^application\/json/.test(contentType)) {
// Response.clone exists to handle this kind of use case
let responseJson = await response.clone().json();
if (responseJson.has_interesting_property) {
analyticsEntries.push('interesting');
}
}
scheduleAnalytics({
requestHeaders,
responseHeaders,
status,
analyticsEntries,
});
return response;
}
async function batchCreateEmbedResource(
request: Request,
next: (request: Request) => Promise<Response>
): Promise<Response> {
if (/target\/url\/pattern/.test(request.url)) {
// Only transform certain kinds of requests
return next(request);
}
let stashedRequest = request.clone();
let rawResponse = await next(request);
let contentType = rawResponse.headers.get('content-type');
if (!/^application\/json/.test(contentType)) {
// Only transform JSON responses
return rawResponse;
}
let transformedResponse = rawResponse.clone();
// also overwrite .text &c. or return a Proxy to avoid cloning.
transformedResponse.json = async function () {
// Read the requested body from a cloned request as request bodies can only be read once
let requestBody = await stashedRequest.json();
// Read the response lazily. This implementation does not handle
let responseBody = await rawResponse.json();
for (let i = 0; i < responseBody.elements.length; ++i) {
// combine the request and response bodies for downstream users.
responseBody.elements[i].resource = requestBody.elements[i];
}
};
return transformedResponse;
}
async function badMiddleware(
request: Request,
next: (request: Request) => Promise<Response>
): Promise<Response> {
let response = await next(request);
// ⛔ Error! ⛔ Don't do this -- it interferes with streaming responses as
// well as subsequent middlewares
//
// use response.clone() to read the body from a middleware
let responseJson = await response.json();
if (responseJson.something) {
// do something...
}
return response;
}
Composing middleware is as easy as composing normal functions.
// Use another middleware conditionally (e.g. only for `/api` requests)
async function limitedAnalytics(
request: Request,
next: (request: Request) => Promise<Response>
): Promise<Response> {
if (request.url.startsWith('/api')) {
return await analyticsMiddleware(request, fetch);
}
return next(request);
}
// Creating and invoking a middleware-enabled fetch
import { buildFetch } from '@data-eden/network';
let fetch = buildFetch([
csrfMiddleware,
queryTunneling,
limitedAnalytics,
batchCreateEbmedResource,
]);
await fetch('///api');
let response = await fetch('/my-api');
There are two patterns for configuring middleware:
If your middleware has setup-time configuration, use a factory function:
export function buildAnalyticsMiddleware(analyticsUrl) {
return new async (
request: Request,
next: (request: Request) => Promise<Response>
) => {
// ...
let analytics = extractAnalytics(request);
scheduleAnalytics(analyticsUrl, analytics);
return next(request);
}
};
If your middleware requires per-request user configuration, you can use custom
HTTP headers as a means of communicating from the user's fetch
call to your
middleware. If needed, your middleware can transform these headers to provide
better APIs to your users than what your server may allow.
async function analyticsMiddleware(
request: Request,
next: (request: Request) => Promise<Response>
): Promise<Response> {
let useCase = request.headers.get('X-Use-Case');
if(useCase !== undefined) {
request.headers.delete('X-Use-Case');
request.headers.set('X-Server-Header-Tracking-abc123': useCase);
}
return next(request);
}
For highly configurable middlewares these techniques can be combined.
v0.18.0 (2023-08-03)
mocker
mocker
FAQs
## Features
We found that @data-eden/network demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 4 open source maintainers collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
Oracle seeks to dismiss fraud claims in the JavaScript trademark dispute, delaying the case and avoiding questions about its right to the name.
Security News
The Linux Foundation is warning open source developers that compliance with global sanctions is mandatory, highlighting legal risks and restrictions on contributions.
Security News
Maven Central now validates Sigstore signatures, making it easier for developers to verify the provenance of Java packages.