5.0 KiB
HttpApi migration
Practical notes for an eventual migration of packages/opencode server routes from the current Hono handlers to Effect HttpApi, either as a full replacement or as a parallel surface.
Goal
Use Effect HttpApi where it gives us a better typed contract for:
- route definition
- request decoding and validation
- typed success and error responses
- OpenAPI generation
- handler composition inside Effect
This should be treated as a later-stage HTTP boundary migration, not a prerequisite for ongoing service, route-handler, or schema work.
Core model
HttpApi is definition-first.
HttpApiis the root APIHttpApiGroupgroups related endpointsHttpApiEndpointdefines a single route and its request / response schemas- handlers are implemented separately from the contract
This is a better fit once route inputs and outputs are already moving toward Effect Schema-first models.
Why it is relevant here
The current route-effectification work is already pushing handlers toward:
- one
AppRuntime.runPromise(Effect.gen(...))body - yielding services from context
- using typed Effect errors instead of Promise wrappers
That work is a good prerequisite for HttpApi. Once the handler body is already a composed Effect, the remaining migration is mostly about replacing the Hono route declaration and validator layer.
What HttpApi gives us
Contracts
Request params, query, payload, success payloads, and typed error payloads are declared in one place using Effect Schema.
Validation and decoding
Incoming data is decoded through Effect Schema instead of hand-maintained Zod validators per route.
OpenAPI
HttpApi can derive OpenAPI from the API definition, which overlaps with the current describeRoute(...) and resolver(...) pattern.
Typed errors
Schema.TaggedErrorClass maps naturally to endpoint error contracts.
Likely fit for opencode
Best fit first:
- JSON request / response endpoints
- route groups that already mostly delegate into services
- endpoints whose request and response models can be defined with Effect Schema
Harder / later fit:
- SSE endpoints
- websocket endpoints
- streaming handlers
- routes with heavy Hono-specific middleware assumptions
Current blockers and gaps
Schema split
Many route boundaries still use Zod-first validators. That does not block all experimentation, but full HttpApi adoption is easier after the domain and boundary types are more consistently Schema-first with .zod compatibility only where needed.
Mixed handler styles
Many current server/instance/*.ts handlers still call async facades directly. Migrating those to composed Effect.gen(...) handlers is the low-risk step to do first.
Non-JSON routes
The server currently includes SSE, websocket, and streaming-style endpoints. Those should not be the first HttpApi targets.
Existing Hono integration
The current server composition, middleware, and docs flow are Hono-centered today. That suggests a parallel or incremental adoption plan is safer than a flag day rewrite.
Recommended strategy
1. Finish the prerequisites first
- continue route-handler effectification in
server/instance/*.ts - continue schema migration toward Effect Schema-first DTOs and errors
- keep removing service facades
2. Start with one parallel group
Introduce one small HttpApi group for plain JSON endpoints only. Good initial candidates are the least stateful endpoints in:
server/instance/question.tsserver/instance/provider.tsserver/instance/permission.ts
Avoid session.ts, SSE, websocket, and TUI-facing routes first.
3. Reuse existing services
Do not re-architect business logic during the HTTP migration. HttpApi handlers should call the same Effect services already used by the Hono handlers.
4. Run in parallel before replacing
Prefer mounting an experimental HttpApi surface alongside the existing Hono routes first. That lowers migration risk and lets us compare:
- handler ergonomics
- OpenAPI output
- auth and middleware integration
- test ergonomics
5. Migrate JSON route groups gradually
If the parallel slice works well, migrate additional JSON route groups one at a time. Leave streaming-style endpoints on Hono until there is a clear reason to move them.
Proposed first steps
- add one small spike that defines an
HttpApigroup for a simple JSON route set - use Effect Schema request / response types for that slice
- keep the underlying service calls identical to the current handlers
- compare generated OpenAPI against the current Hono/OpenAPI setup
- document how auth, instance lookup, and error mapping would compose in the new stack
- decide after the spike whether
HttpApishould stay parallel, replace only some groups, or become the long-term default
Rule of thumb
Do not start with the hardest route file.
If HttpApi is adopted here, it should arrive after the handler body is already Effect-native and after the relevant request / response models have moved to Effect Schema.