Something went wrong. Try again.
Specification for the Fetchable module interface
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302<!doctype html><html lang="en"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta http-equiv="X-UA-Compatible" content="ie=edge" /> <title>Fetchable specification</title>
<style> :root { color-scheme: dark; --bg: #0a0a0a; --surface: #111; --fg: #ededed; --muted: #8a8a8a; --border: #1f1f1f; }
*, *::before, *::after { box-sizing: border-box; }
html, body { margin: 0; }
body { font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; font-size: 16px; line-height: 1.65; color: var(--fg); background: var(--bg); max-width: 72rem; margin-inline: auto; padding: 4rem 1.5rem 6rem; text-wrap: pretty; }
header { text-align: center; margin-block-end: 4rem; }
h1 { font-size: clamp(1.5rem, 4vw, 2rem); font-weight: 600; margin: 0; text-wrap: balance; }
.subtitle { margin-block-start: 0.5rem; font-size: 0.875rem; font-weight: 400; color: var(--muted); }
main { border-block-start: 1px solid var(--border); padding-block-start: 2.5rem; display: flex; flex-direction: column; gap: 1.5rem; }
p, h2, ul { margin: 0; }
main :is(p, h2, ul) { max-width: 75ch; margin-inline: auto; }
h2 { font-size: 1rem; font-weight: 600; color: var(--muted); }
ul { padding-inline-start: 1.25rem; }
li + li { margin-block-start: 0.25rem; }
a { color: inherit; text-decoration-color: var(--muted); text-decoration-thickness: 1px; text-underline-offset: 3px; transition: text-decoration-color 120ms; }
a:hover { text-decoration-color: var(--fg); }
code { font-family: inherit; }
:is(p, li) code { padding: 0.125rem 0.375rem; background: var(--surface); border: 1px solid var(--border); border-radius: 4px; font-size: 0.875em; }
.code-block { margin: 0; font-size: 0.8125rem; line-height: 1.6; padding: 1rem 1.25rem; background: var(--surface); border: 1px solid var(--border); border-radius: 8px; max-width: 45rem; margin-inline: auto; overflow-x: auto; }
abbr { text-decoration: none; cursor: help; }
footer { margin-block-start: 4rem; padding-block-start: 2rem; border-block-start: 1px solid var(--border); text-align: center; font-size: 0.8125rem; color: var(--muted); }
footer a { display: inline-flex; align-items: center; gap: 0.5rem; }
footer img { width: 14px; height: 14px; } </style> </head>
<body> <header> <h1>Fetchable</h1> <p class="subtitle">standard interface for request entry points</p> </header> <main> <p> Fetchable is a type interface that request entry point <abbr title="EcmaScript">ES</abbr> modules may implement to ensure compatiblity with many platforms, runtimes, frameworks, and other tools. It is designed to be simple, flexible, and extensible. It is documented here as a reference to encourage adoption and interoperability across the ecosystem. </p>
<h2>Definitions</h2>
<p> A <strong>Fetchable module</strong> is an ECMAScript module whose default export is an object with a <code>fetch</code> property conforming to the <code>FetchHandler</code> interface (<a href="https://blog.val.town/blog/the-api-we-forgot-to-name/" target="_blank" >ref</a >). This method is intended to be invoked to handle an incoming HTTP request. </p>
<pre class="code-block">interface Fetchable { default: { fetch(request: Request, ...extra: unknown[]): Promise<Response> | Response }}</pre>
<p> The first argument MUST be a <a href="https://developer.mozilla.org/en-US/docs/Web/API/Request">Web Request</a>. The return value MUST be either a <a href="https://developer.mozilla.org/en-US/docs/Web/API/Response">Web Response</a> or a promise resolving to a Web Response. </p>
<p> Invokers <em>may</em> pass additional custom arguments. Fetchable modules <em>may</em> have additional properties on their default export. </p>
<h2>Example</h2>
<pre class="code-block">// entrypoint.tsexport default { async fetch(req: Request): Promise<Response> { return new Response(`Hello, ${req.headers.get("User-Agent")}!`) }}</pre>
<h2>Interoperable with...</h2>
<ul> <li> <a href="https://oakserver.org/acorn">Acorn</a> </li> <li> <a href="https://bun.sh/docs/runtime/http/server">Bun</a> </li> <li> <a href="https://developers.cloudflare.com/workers/runtime-apis/handlers/fetch/" >Cloudflare Workers</a > </li> <li> <a href="https://docs.deno.com/runtime/reference/cli/serve/">Deno</a> </li> <li> <a href="https://docs.deno.com/deploy/reference/runtime/">Deno Deploy</a> </li> <li> <a href="https://elysiajs.com/">Elysia</a> </li> <li> <a href="https://h3.dev/guide/api/h3">H3</a> </li> <li> <a href="https://hono.dev/docs/api/hono#fetch">Hono</a> </li> <li> <a href="https://itty.dev/itty-router/getting-started">itty-router</a> </li> <li> <a href="https://docs.netlify.com/build/functions/overview/">Netlify Functions</a> </li> <li> <a href="https://nitro.build/docs/server-entry">Nitro</a> </li> <li> <a href="https://jsr.io/@oak/oak/doc">Oak</a> </li> <li> <a href="https://docs.rwsdk.com/reference/sdk-worker">RedwoodSDK</a> </li> <li> <a href="https://www.rivet.dev/docs/general/http-server/">RivetKit</a> </li> <li>SolidStart (coming soon)</li> <li> <a href="https://srvx.h3.dev/guide#quick-start-cli">srvx</a> </li> <li> <a href="https://tanstack.com/start/latest/docs/framework/react/guide/server-entry-point" >TanStack Start</a > </li> <li> <a href="https://vercel.com/docs/functions">Vercel Functions</a> </li> </ul> </main>
<footer> <a href="https://tangled.org/philippeserhal.com/fetchable" target="_blank" rel="noopener"> <img src="public/tangled.svg" alt="" /> Source on Tangled </a> </footer>
<script type="module"> import { codeToHtml } from "https://esm.sh/shiki@4.0.2";
const els = document.querySelectorAll(".code-block"); if (els.length === 0) { console.warn("Could not find code blocks to highlight"); } const tmpl = document.createElement("template"); for (const el of els) { const html = await codeToHtml(el.textContent, { lang: "typescript", theme: "catppuccin-mocha", }); tmpl.innerHTML = html; el.replaceChildren(tmpl.content.firstElementChild.querySelector("code")); } </script> </body></html>