Overview
Featul’s API layer uses jstack, a type-safe RPC framework built on top of Hono. jstack provides end-to-end type safety from server to client with minimal boilerplate.Why jstack?
- Type Safety: Full TypeScript inference from server to client
- Performance: Built on Hono, optimized for edge runtimes
- DX: Minimal API surface, intuitive patterns
- Flexibility: Works with any transport layer
- Serialization: SuperJSON support for complex types (Dates, Maps, Sets)
Architecture
Core Setup
Frompackages/api/src/jstack.ts:10:
Middleware
Database Middleware
Injects database client into context:ctx.db for database access.
Authentication Middleware
Frompackages/api/src/jstack.ts:16:
ctx.session with user information.
Procedure Types
Frompackages/api/src/jstack.ts:56:
- No authentication required
- Has database access via
ctx.db - Used for public data (viewing boards, posts)
- Requires authentication
- Has database access via
ctx.db - Has session access via
ctx.session - Used for protected actions (creating posts, voting)
Router Structure
Router Organization
Routers are organized by domain inpackages/api/src/router/:
Router Definition Pattern
Frompackages/api/src/router/workspace.ts:52:
Router Aggregation
Frompackages/api/src/index.ts:1:
Input Validation
Zod Schemas
All inputs are validated with Zod inpackages/api/src/validators/:
Using Validators
Client Usage
Type-Safe Client
Client is auto-generated from router types:With React Query
Response Patterns
JSON Response
For simple data:SuperJSON Response
For complex types (Date, Map, Set, etc.):Error Responses
Cache Headers
Common Patterns
Permission Checking
Frompackages/api/src/router/workspace.ts:27:
Pagination
Aggregations
Frompackages/api/src/router/workspace.ts:128:
File Downloads
Frompackages/api/src/router/workspace.ts:616:
Best Practices
Naming Conventions
- Routers:
createXyzRouter()factory functions - Procedures: Verb-based names (
create,update,delete,list) - Validators:
{action}{Resource}InputSchema(e.g.,createWorkspaceInputSchema)
Error Handling
Always throwHTTPException with appropriate status codes: