examples / apis

Hello API

A minimal JSON API in one file. The 30-second intro to services.

denohttpjson

Every Frontback service is a single default export: a fetch-style handler that takes a Request and returns a Response, the same signature you know from the web platform. This example routes on the URL pathname to serve a JSON index, a greeting endpoint with a path parameter, the server time, and an echo endpoint that reads a JSON body.

Deploying it creates one project with one service. No configuration, no secrets, no database. The service is live at its own URL a few seconds after deploy. Start here, then move on to the storage and cron examples.

code
main.ts
// A Frontback service is one file with one default export: a fetch-style
// handler that takes a Request and returns a Response. Deploy it and it
// is live at its own URL a few seconds later.
//
// This service is a tiny JSON API that routes on the URL pathname.

export default async (req: Request): Promise<Response> => {
  const { pathname } = new URL(req.url);

  // GET / -> a small index of what this API can do.
  if (pathname === "/") {
    return json({
      name: "hello-api",
      endpoints: ["GET /", "GET /hello/:name", "GET /time", "POST /echo"],
    });
  }

  // GET /hello/:name -> a path parameter is just a slice of the pathname.
  if (req.method === "GET" && pathname.startsWith("/hello/")) {
    const name = decodeURIComponent(pathname.slice("/hello/".length));
    if (!name) return json({ error: "Add a name, e.g. /hello/ada" }, 422);
    return json({ message: `Hello, ${name}!` });
  }

  // GET /time -> the current server time.
  if (req.method === "GET" && pathname === "/time") {
    return json({ now: new Date().toISOString() });
  }

  // POST /echo -> read the JSON body and send it straight back.
  if (req.method === "POST" && pathname === "/echo") {
    const body = await req.json().catch(() => null);
    if (body === null) return json({ error: "Send a JSON body" }, 422);
    return json({ received: body });
  }

  // Anything else: answer with a 4xx, not a 5xx — an expected miss should
  // not mark the run as failed in the dashboard.
  return json({ error: "Not found", hint: "GET /hello/world" }, 404);
};

// One helper keeps every response consistent: pretty JSON + charset header.
function json(data: unknown, status = 200): Response {
  return new Response(JSON.stringify(data, null, 2) + "\n", {
    status,
    headers: { "content-type": "application/json; charset=utf-8" },
  });
}

Go beyond what seems possible.