Skip to main content
Ant exposes fetch() as a global, so you can make HTTP requests from anywhere in your script without importing anything. The API is fully WinterTC-compatible, meaning it behaves the same as in modern browsers and other standards-compliant runtimes. You can use it in top-level scripts, inside server request handlers, or anywhere async code runs.

Basic GET request

The simplest call passes a URL string and awaits the response.
const response = await fetch('https://ifconfig.co/json');
const data = await response.json();
console.log(data.ip);
The response.json() method parses the body as JSON and resolves with the result. This is the pattern used throughout the Ant examples:
const fetchJson = (url, options) => fetch(url, options).then(r => r.json());

const { ip } = await fetchJson('https://ifconfig.co/json');
console.log(ip);

POST with a JSON body

Pass an options object as the second argument to set the method, body, and headers.
const fetchJson = (url, options) => fetch(url, options).then(r => r.json());

const { json, headers } = await fetchJson('https://httpbingo.org/post', {
  method: 'POST',
  body: JSON.stringify({ runtime: 'ant' }),
  headers: {
    'Content-Type': 'application/json',
    'User-Agent': 'ant/alpha (ant)'
  }
});

console.log(JSON.stringify(json));
console.log(JSON.stringify(headers));
Always set Content-Type: application/json when sending a JSON body. The runtime does not add this header automatically.

Reading the response

A Response object gives you several ways to read the body depending on what the server returns.
const res = await fetch('https://api.example.com/data');
const obj = await res.json();

Custom headers

Use the headers option to pass any HTTP headers with your request.
const res = await fetch('https://api.github.com/zen', {
  headers: {
    'Accept': 'application/json',
    'Authorization': `Bearer ${process.env.GITHUB_TOKEN}`
  }
});

const text = await res.text();
console.log(text);
You can also construct a Headers object explicitly:
const headers = new Headers();
headers.set('Content-Type', 'application/json');
headers.set('X-Request-ID', crypto.randomUUID());

const res = await fetch('https://api.example.com/endpoint', {
  method: 'POST',
  headers,
  body: JSON.stringify({ hello: 'world' })
});

Using Request and Response objects

You can construct a Request object when you want to reuse or inspect request details before sending.
const req = new Request('https://api.example.com/users', {
  method: 'GET',
  headers: { 'Accept': 'application/json' }
});

const res = await fetch(req);
const users = await res.json();
Response.json() is a static helper that creates a JSON response — most useful inside server handlers, but also available anywhere:
const res = Response.json({ status: 'ok', runtime: 'ant' });
console.log(res.headers.get('Content-Type')); // application/json

Checking response status

Always check response.ok or response.status before reading the body in production code.
const res = await fetch('https://api.example.com/resource');

if (!res.ok) {
  throw new Error(`Request failed: ${res.status} ${res.statusText}`);
}

const data = await res.json();
response.ok
boolean
true when status is in the 200–299 range.
response.status
number
HTTP status code (e.g. 200, 404, 500).
response.statusText
string
HTTP status message (e.g. "OK", "Not Found").
response.headers
Headers
The response headers as a Headers object.

fetch inside a server handler

You can call fetch from within a server fetch handler to proxy or compose data from upstream services. Ant handles the concurrent I/O transparently.
addRoute(router, 'GET', '/echo', async () => {
  const res = await fetch('http://localhost:8000/meow');
  return new Response(await res.text(), {
    headers: { 'X-Ant': 'meow' }
  });
});
Similarly, you can fetch external APIs and return the result directly:
addRoute(router, 'GET', '/zen', async () => {
  const response = await fetch('https://api.github.com/zen');
  return new Response(await response.text());
});

addRoute(router, 'GET', '/api/v2/demo', async () => {
  const data = await fetch('https://themackabu.dev/test.json');
  return Response.json(await data.json());
});

Running multiple requests in parallel

Use Promise.all to fire multiple requests concurrently and wait for all of them.
const fetchJson = (url, options) => fetch(url, options).then(r => r.json());

await Promise.all([
  fetchJson('https://ifconfig.co/json').then(({ ip }) => console.log('ip:', ip)),
  fetchJson('https://themackabu.dev/test.json').then(d => console.log('test:', d)),
  fetchJson('https://httpbingo.org/post', {
    method: 'POST',
    body: JSON.stringify({ runtime: 'ant' }),
    headers: { 'Content-Type': 'application/json', 'User-Agent': 'ant/alpha (ant)' }
  }).then(({ json }) => console.log('post echo:', json))
]);