← Templates

A Hono REST API in one Function, on your own database

A Hono REST API with six routes for customers and their orders, checked with zod. The data lives in your own Supabase tables, and the whole API deploys and rolls back as one unit.

You want a REST API, not one deploy per route

On many platforms each route is its own function, with its own version and its own rollback. Here one Function gets every path under its address. All six routes ship together, and the data they write stays in a database you own.

The whole template is public. Read it before you trust it.

Or scaffold it

$ npx wawesome init --template rest-api
$ npx wawesome deploy

What you get

A Function called customers that answers six routes:

GET    /              list the customers
POST   /              create one
GET    /:id           read one
PUT    /:id           replace one
DELETE /:id           delete one
GET    /:id/orders    list one customer's orders

The routes are in src/index.ts, written with Hono. The shape of a customer is the zod schema at the top of that file:

const CustomerDraft = z.object({
  name: z.string().trim().min(1).max(200),
  email: z.email().max(320),
});

A body that doesn’t match it gets a 422 that names each wrong field. An id that isn’t a customer gets a 404. The tests are in src/index.test.ts.

The data lives in two tables, customers and orders, in your own Supabase project. schema.sql creates them, with one customer and two orders to start with. src/supabase.ts talks to Supabase’s REST API with plain fetch. If Supabase refuses a request, the answer is a 500 and the reason is in your logs.

Run it

npx wawesome init --template rest-api

It offers to log you in if you aren’t. Then it asks for a Function name, customers by default, and an App slug. If you haven’t deployed yet, it offers to change your workspace address, which locks at your first deploy. Then it asks for two values:

  • SUPABASE_URL, your project’s URL, like https://abcd.supabase.co. It’s under Project Settings → Data API. We open that one host to your App’s outbound calls.
  • SUPABASE_KEY, the secret key, which starts with sb_secret_. It’s under Project Settings → API Keys. We store it as a secret. The Function needs this key because schema.sql turns on row-level security with no policy, and the publishable key can’t read or write anything. Set the publishable key by mistake and every route answers 503, naming the key it needs.

If you don’t have a Supabase project yet, leave both blank. Every route then answers 503 until you set them.

Then it deploys. Before you use the API, open your project’s SQL Editor, paste in schema.sql and run it. If you left the values blank, set them now:

npx wawesome env set SUPABASE_URL https://<project-ref>.supabase.co
npx wawesome env set SUPABASE_KEY sb_secret_... --secret

Then try it, with the address init printed:

API=https://api.wawesome.io/x/<workspace>/rest-api/customers
curl "$API"
curl -X POST "$API" -H 'Content-Type: application/json' \
  -d '{"name":"Nadia Petrova","email":"nadia@example.com"}'

What to change first

The zod schema in src/index.ts, so a customer has the fields you need. A new field needs a column in schema.sql too. A new route is one more app.get(...) or app.post(...) in the same file.

To use a database other than Supabase, change src/supabase.ts. A Function can only reach it with an HTTPS request made with fetch, and its host is refused until you open it. See Where your data goes and Outbound calls.

What it doesn’t do

Every route is public, so anyone with the address can read and delete your customers. Add authentication before you put real data in. There’s no CORS, so a browser on another origin can’t call it until you set the headers. The list routes return every row, with no pagination.

  • rest
  • api
  • hono
  • zod
  • crud
  • database
  • supabase
  • typescript

Ready in about a minute

Sign in with GitHub, deploy, and get a public HTTPS endpoint.

Deploy this template