138 lines
5.0 KiB
Markdown
138 lines
5.0 KiB
Markdown
# 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.
|
|
|
|
- `HttpApi` is the root API
|
|
- `HttpApiGroup` groups related endpoints
|
|
- `HttpApiEndpoint` defines 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.ts`
|
|
- `server/instance/provider.ts`
|
|
- `server/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 `HttpApi` group 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 `HttpApi` should 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.
|