examples/storefront Public
storefront
The API behind a small online shop, running on Cloudflare Workers. Products, carts and orders live in D1, the search index in a second D1 database, product images in R2, and payments go through Stripe.
There are three Workers:
storefront-api(src/) is the public API and the only Worker that writes to the database.storefront-stripe-webhook(workers/stripe-webhook/) receives Stripe's events and settles orders through storefront-api'sOrdersServiceentrypoint.storefront-fulfilment(workers/fulfilment/) consumes theorder-eventsqueue and sends paid orders to the warehouse.
The order fulfilment flow on the Architecture tab follows a payment through all three.
It is a plain fetch handler with a small router, no framework, and the tests run the real SQL migrations on Node's built-in SQLite, so npm test needs nothing but Node 24.
Running it
npm install
npm test
npm run typecheck
To run the API locally with a small seeded catalog:
npm run db:migrate
npm run db:seed
echo 'ADMIN_TOKEN=dev-admin-token' > .dev.vars
npm run dev
curl -X POST localhost:8787/admin/search/rebuild -H 'authorization: Bearer dev-admin-token'
Product images are served from the bucket's custom domain, IMAGES_URL in wrangler.jsonc. Checkout needs Stripe: add STRIPE_SECRET_KEY to .dev.vars with a secret key from your Stripe account's test mode.
The guide in .rebasely/kb/guides/local-dev.md covers the other two Workers and the cron trigger. To add a product and look at the catalog:
curl -X PUT localhost:8787/admin/products/wool-socks \
-H 'authorization: Bearer dev-admin-token' -H 'content-type: application/json' \
-d '{"name":"Wool socks","price_cents":1800,"stock":40}'
curl localhost:8787/products
API
| Method and path | What it does |
|---|---|
GET /products |
Active products by name, a page at a time: ?limit= (1 to 100, default 24) and ?after= the previous page's next |
GET /products/:id |
One active product |
GET /search |
Active products matching ?q=, best match first, up to ?limit= |
PUT /admin/products/:id |
Create or replace a product (admin token) |
PUT /admin/products/:id/image |
Upload the product's image (admin token) |
POST /admin/search/rebuild |
Refill the search index from the catalog (admin token) |
POST /carts |
A new, empty cart |
GET /carts/:id |
A cart with its lines and totals |
PUT /carts/:id/items/:product |
Set a quantity, { "quantity": n } |
DELETE /carts/:id/items/:product |
Remove a line |
POST /carts/:id/checkout |
Create the order and its PaymentIntent, { email, ship_to } |
GET /orders/:id |
An order and its status |
Errors are JSON, { "error": "<code>", "message": "..." }, with extra fields where they help (an out_of_stock error says how many are available).
Layout
src/ storefront-api: router, catalog, carts, images, checkout, orders
workers/ the other Workers, each with its own wrangler.jsonc
migrations/ D1 schema, applied in order
search/ the search index's schema (search/migrations/)
test/ node --test suites and the D1 and R2 stand-ins
.rebasely/ architecture map, knowledge base and CI workflow
The knowledge base in .rebasely/kb explains how each part works and why; start at its index.
License
MIT