Skip to content

Instantly share code, notes, and snippets.

@artalar
Created January 29, 2024 14:06
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save artalar/b85e7a6a94cc1136aa93b89810c4d760 to your computer and use it in GitHub Desktop.
Save artalar/b85e7a6a94cc1136aa93b89810c4d760 to your computer and use it in GitHub Desktop.
reatomFetch
export type UrlSearchParamsInit = ConstructorParameters<
typeof URLSearchParams
>[0];
export interface FetchRequestInit<
Result = unknown,
Params = unknown,
Body = unknown
> extends RequestInit {
url?: string | URL;
origin?: string;
transport?: typeof globalThis.fetch;
getResult?: (response: Response) => Result | Promise<Result>;
getParams?: (params: Params) => UrlSearchParamsInit;
getBody?: (body: Body) => BodyInit;
}
export class FetchRequest<
Result = unknown,
Params = void,
Body = void
> extends Request {
static defaults = {
origin: globalThis.location?.toString(),
transport: globalThis.fetch,
method: "get",
headers: { Accept: "application/json" },
getResult(response) {
if (Math.floor(response.status / 100) - 2) {
throw new Error(
`HTTP Error: ${response.statusText ?? response.status}`
);
}
const ct = response.headers.get("Content-Type");
if (ct !== "application/json") {
throw new Error(
`Expected Content-Type to be "application/json", got "${ct}"`
);
}
return response.json();
},
getParams: (x) => x as UrlSearchParamsInit,
getBody: (body) =>
body &&
typeof body === "object" &&
Reflect.getPrototypeOf(body) &&
!Array.isArray(body)
? (body as BodyInit)
: JSON.stringify(body),
} satisfies FetchRequestInit;
init: Required<FetchRequestInit<Result, Params, Body>>;
constructor(init: FetchRequestInit<Result, Params, Body>) {
Object.assign(init, FetchRequest.defaults, init);
const url = new URL(init.origin!, init.origin);
super(url, init);
// FIXME prefill the init
this.init = init;
}
clone(): FetchRequest<Result, Params, Body> {
return new FetchRequest(this.init);
}
fetch(options: Params & Body): Promise<Response> {
const { transport, getParams, getBody, getResult, ...init } = this.init;
const url = new URL(init.url);
for (const [key, value] of new URLSearchParams(getParams(options))) {
url.searchParams.set(key, value);
}
init.body ??= getBody(options);
return transport(url, init).then(getResult);
}
}
fetch('', {signal})
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment