Routing
Semitra routing is declarative and Rails-shaped, but targeted at Cloudflare-native JSON APIs that pair with the opinionated React Router 7 frontend stack.
Route DSL
Section titled “Route DSL”Generated starter apps default to a versioned JSON API surface with api(...):
import { api, drawRoutes, get } from "@semitra/cli";
export default drawRoutes(() => { api(() => { get("health", "health#show"); });});The example app shows a broader reference surface:
import { drawRoutes, get, namespace, post, resources } from "@semitra/cli";
export default drawRoutes(() => { resources("posts"); get("health", "health#show"); post("rpc", "rpc#create");
namespace("api", () => { namespace("v1", () => { resources("posts"); get("health", "health#show"); }); });});That keeps the public surface compact: a posts resource, a health check, an RPC endpoint, and a versioned API namespace all map cleanly to controller actions.
Route concepts
Section titled “Route concepts”resources("posts")generates conventional CRUD-style routes.api()applies the default/api/v1JSON route shape for generated starters.get()andpost()create explicit routes.namespace()groups paths and controller names.- route metadata is compiled into the generated app manifest.
Semitra also supports route defaults such as version and format through the DSL.
The reference app uses the same shape in config/routes.ts:
resources("posts");get("health", "health#show");post("rpc", "rpc#create");
namespace("api", () => { namespace("v1", () => { resources("posts"); get("health", "health#show"); });});What routing resolves
Section titled “What routing resolves”Each route definition ultimately resolves:
- HTTP method
- path
- controller identifier
- action name
- optional name
- optional version or format metadata
- optional params contract
- optional middleware references
That metadata is what SemitraApp uses to instantiate the correct controller
and dispatch the action.
Route params and request params
Section titled “Route params and request params”Semitra merges:
- path params
- query params
- request body params
The merged set is exposed through this.params. If a route defines a params
contract, Semitra validates it before controller execution and stores the typed
result in validatedParams.
Routing discipline
Section titled “Routing discipline”Keep routes declarative:
- route to controllers, not arbitrary functions
- use versioned namespaces when you want public API stability
- let controllers own orchestration
- let route params contracts define request shape early