![PyPI Now Supports iOS and Android Wheels for Mobile Python Development](https://cdn.sanity.io/images/cgdhsj6q/production/96416c872705517a6a65ad9646ce3e7caef623a0-1024x1024.webp?w=400&fit=max&auto=format)
Security News
PyPI Now Supports iOS and Android Wheels for Mobile Python Development
PyPI now supports iOS and Android wheels, making it easier for Python developers to distribute mobile packages.
@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.16.3 (2023-07-19)
mocker
mocker
FAQs
## Features
The npm package @data-eden/network receives a total of 1 weekly downloads. As such, @data-eden/network popularity was classified as not popular.
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
PyPI now supports iOS and Android wheels, making it easier for Python developers to distribute mobile packages.
Security News
Create React App is officially deprecated due to React 19 issues and lack of maintenance—developers should switch to Vite or other modern alternatives.
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.