Endpoints

A `.ts` File in `src/pages/` Is an API Route

Endpoints

Export `GET`, `POST`, etc., from a `.ts` file under `src/pages/`, return a `Response`, and Astro routes requests to it.

4 min read Level 2/5 #astro#endpoints#api
What you'll learn
  • Author a GET endpoint
  • Read query params and the body
  • Return JSON or plain text

A .ts (or .js) file in src/pages/ is an endpoint — an API route, not a page. Export functions named after HTTP methods, return a Response.

A GET Endpoint

// src/pages/api/hello.ts
import type { APIRoute } from "astro";

export const GET: APIRoute = () => {
  return new Response(JSON.stringify({ hello: "world" }), {
    headers: { "content-type": "application/json" },
  });
};

Visit /api/hello{"hello":"world"}.

For static builds, endpoints must be marked export const prerender = false (or the site must be in server mode), otherwise the endpoint is treated as static and only the build-time response is shipped.

Reading Query Params

// src/pages/api/search.ts
export const prerender = false;

export const GET: APIRoute = ({ url }) => {
  const q = url.searchParams.get("q") ?? "";
  return new Response(JSON.stringify({ q, results: [/* ... */] }), {
    headers: { "content-type": "application/json" },
  });
};

The context ({ url, params, request, cookies, redirect, ... }) is the same as in pages.

POST Endpoint

// src/pages/api/contact.ts
export const prerender = false;

export const POST: APIRoute = async ({ request }) => {
  const body = await request.json();
  if (!body.email) {
    return new Response(JSON.stringify({ error: "email required" }), {
      status: 400,
      headers: { "content-type": "application/json" },
    });
  }
  await saveContact(body);
  return new Response(JSON.stringify({ ok: true }), {
    headers: { "content-type": "application/json" },
  });
};

Convenience — JSON Response

Astro 4+ exports a Response.json(...) helper from the platform:

return Response.json({ ok: true });
return Response.json({ error: "bad" }, { status: 400 });

Less boilerplate, same result.

Dynamic Endpoint Routes

Brackets work in .ts files too:

// src/pages/api/users/[id].ts
export const GET: APIRoute = async ({ params }) => {
  const user = await db.users.findById(params.id);
  return Response.json(user);
};

Streaming Responses

You can return a Response with a streaming body — server-sent events, large NDJSON dumps, etc. The Response API is the same standard one browsers and Node both implement.

Up Next

A common use of endpoints — handling form submissions.

Forms →