The Tool Desk
Outbyte PC Repair FREERepair Windows errors before they cause bigger problemsFix Now →Outbyte Driver Updater FREEFix the driver behind crashes, sound loss and screen glitchesFind Drivers →iTechGuides is reader-supported. When you buy through links on our site, we may earn an affiliate commission. As an Amazon Associate I earn from qualifying purchases. Learn more
In TeamTavern, each endpoint is declared once as a PureScript route type, then imported by both the Node server and the Halogen browser app. The server uses it to shape handlers; the client uses it to build requests and interpret declared responses. This catches many disagreements about paths, request bodies, and response shapes at compile time—but it cannot describe every response a browser might receive or prove that the application works correctly.
What does it mean to share an HTTP API type?
TeamTavern is a team-finding site for online games. Its project announcement describes a browser app built with Halogen and a Node API server, with both written in PureScript in one codebase and built using one spago build. The code is open under AGPL-3.0. Its routing library, Jarilo, is part of the maintainer’s purescript-bklaric collection. Project announcement · Code and library details
The design is comparable in spirit to Haskell’s Servant: a route is type-level data, not a runtime route value. Its declaration combines an HTTP method, path, optional request body, and the response cases the endpoint is allowed to produce. The server and client each interpret the same declaration for their own work.
Windows Errors? Fix Them Before They Spread
Repair common Windows errors and clear accumulated junk for a smoother, more stable PC - no reinstall needed.Free scan · no reinstallOutdated Drivers Are Slowing You Down
One free scan finds every outdated or missing driver and matches the right update for your exact hardware.Free scan · exact hardware matchHow is an endpoint declared?
A request and its response cases
The StartSession example declares a POST request to /sessions. Its JSON body is represented by a variant, and its possible responses include 204 No Content, a 400 response with typed error content, and 500. The route therefore records more than a URL: it specifies the expected shape of the exchange. Route and code examples
#1 Best Overall
Typed path captures
A separate ViewPost example uses literal path segments plus named captures: a game handle typed as String and a post ID typed as Int. Keeping these route declarations in a route module lets both sides import the same request and response data types.
How does the server use the route?
The server assembles routes into a named route collection and passes that collection, along with a handler record, to serve. Type-class constraints derive the handler record’s fields, inputs, and allowed response variants from the collection.
- For a captured path value, the handler receives a record field with the type declared in the route. In the
ViewPostcase, the router parses the integer capture before calling application code; a non-integer segment is rejected before the handler runs. - For a JSON request body, decoding produces the route’s declared request type before the handler receives it.
- The handler’s response type is restricted to the responses declared by the route. Returning an undeclared response is rejected by the type checker.
Adding a route to the collection also means the server needs a corresponding handler before the server builds. The type-level route declaration thus constrains both dispatch and the implementation record, rather than merely documenting an endpoint.
Quick wins for a faster PC:
Scan for outdated or missing drivers - takes under a minuteDriver Scan →Clear out junk files and repair common Windows errorsFree Scan →Fix the driver behind crashes, sound loss and screen glitchesFind Drivers →How does the client use the same route?
On the browser side, a Fetch type class reads the route declaration to determine the HTTP method, construct the URL from typed path and query records, encode a request body, and decode declared responses. A ViewPost call must supply its handle and ID as the types specified by the route. Leaving out the ID or passing it as a string instead of an integer is a compile-time error. Client fetch examples
This is the central benefit of sharing the declaration: the client cannot quietly drift to a different path-field or body shape while still type-checking against that route, and the handler cannot return a response variant the route does not allow.
Which API mismatches can the compiler catch?
The TeamTavern article reports 47 routes in the example site; that is a project-specific count reported by the author in 2026, not a benchmark or a general measure of route-type systems. The author describes these kinds of changes as compile-time checks: TeamTavern’s change examples
- Renaming a response field exposes server handlers and client readers that still use the old field.
- Adding a path capture requires existing client calls to provide the new path field.
- Removing a response exposes handlers and clients that still use that response.
- Adding a route to the server’s route collection requires a handler for it before the build succeeds.
- Returning a response not declared for a route fails to type-check.
These checks are valuable because they turn certain API-shape disagreements into build failures rather than waiting for a request to exercise the mismatch. They do not establish that the handler’s logic is correct or that it can successfully produce its declared output.
Does adding a response force every client to handle it?
Not necessarily. The article notes that client call sites using onMatch with a default branch can continue to compile after a response case is added. That style favors concise handling and forward compatibility, but it may leave a new case covered by the fallback. Using exhaustive match instead requires call sites to spell out every response case, so adding one makes incomplete handling visible to the compiler. This is a trade-off between less repetitive code and explicit handling of every declared case. Response-handling examples
What remains outside the route type?
“The route type describes what my server sends. It does not describe everything a browser can receive.” — Branimir Klarić, article author, DEV Community, September 30, 2026. Article on route-type boundaries
Rank #4
- Infrastructure responses: TeamTavern’s example includes a reverse proxy that rejects request bodies over 64 KB with
413, a status not declared by the route. That limit and response are specific to the example, not a general proxy setting. Reverse-proxy example - Deployment skew: During a brief rollout mismatch, a stale client can talk to a newer server. An undeclared status is treated as a
FetchError, not as one of the route’s typed response cases. - Unexpected-status logging: The client reports unexpected responses and unanticipated common error statuses, but expected status labels are plain strings. A misspelled label can compile and only become apparent in logs if that response occurs.
- Database results: SQL rows are decoded at runtime. If a query returns a shape that does not match the expected data, it fails when the query runs; the route declaration does not validate database rows during compilation.
- Application behavior: Matching API types does not prove that a handler successfully produces its promised output or that a page behaves correctly. Those still need testing.
The bounded claim is that a shared route type catches certain disagreements between the API shape declared by the server and the code implementing or consuming that shape. It is not a proof that every network outcome or application behavior is correct.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Can route declarations support other tools?
Because a route collection contains structured endpoint information, it can serve as input for other generated artifacts. The TeamTavern article describes OpenAPI documentation, endpoint lists for tests, TypeScript declarations, and mock servers as possible derivations—not features that TeamTavern currently ships. TeamTavern does not generate OpenAPI because its own pages are its only client. The author identifies body schemas as a harder part of generation: records, arrays, optional values, and variants need to align with the JSON codec’s actual representation. Derived-use discussion
The project also has a small RequestLine class that derives a method-and-path string for failure reporting without logging query strings, which can contain one-time email codes. This is a practical use of route structure that does not require exposing query values in logs.
Best Value
When is this approach a good fit?
A route-type design is most useful when one team controls both sides of an API and wants the compiler to enforce consistency as routes evolve. It makes endpoint changes more explicit and can remove repeated hand-maintained assumptions about paths, payloads, and response variants.
- Choose exhaustive response matching when clients should visibly revisit handling whenever the declared response set changes.
- Choose a default branch when a fallback is intentional and concise handling matters more than forcing every call site to address each new case.
- Keep runtime validation, error handling, and page-level tests: route types constrain declared API shapes, not infrastructure behavior, stored data, or user-visible correctness.
The implementation trades some type-level and route-module design effort for earlier feedback on a meaningful class of client/server mismatches. The TeamTavern example demonstrates the mechanism and its limits; its route count and author-reported experience are not independent evidence of a performance or productivity gain.
Quick Recap
Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.
Free tools Windows power users keep installed
One-click scans. No signup required.

