Route
src/routes/api.products.route.ts
Map GET /api/products/:id to the API Controller and JSON View.
defineRoute({ method: 'GET', path: '/api/products/:id',
controller: getProduct, view: renderProductJson })
RCMVThe same RCMV path works without a human-facing screen. The View still matters: it owns the public JSON representation, headers, and HTTP status.
Open the Database API demoThe JSON View owns field names, status codes, headers, error envelopes, and version stability. The Model’s database row remains private; the API representation is deliberately public.
Map GET /api/products/:id to the API Controller and JSON View.
defineRoute({ method: 'GET', path: '/api/products/:id',
controller: getProduct, view: renderProductJson })Request one record from the Model and choose ready or missing without shaping JSON.
const result = await findProduct(context.params.id, env.DB)
return result.status === 'found'
? controller.ready(result.data)
: controller.missing()Query the database, validate the row, and return the same standard Model result used by DOM features.
const row = await db.prepare('SELECT * FROM products WHERE id = ?')
.bind(id).first()
return row ? model.found(Product.parse(row)) : model.missing()Create the stable public JSON contract. There is no visual interface, but representation remains a View responsibility.
return Response.json(
outcome.status === 'ready'
? { data: outcome.data }
: { error: { code: 'PRODUCT_NOT_FOUND' } },
{ status: outcome.status === 'ready' ? 200 : 404 })