REST API Style Guide
Base Structure
Section titled “Base Structure”- Use Hono as the framework
- Each route file should export a Hono app instance
- Group related endpoints in a single route file
- Use TypeScript for type safety
Route Organization
Section titled “Route Organization”const app = new Hono<{ Bindings: Env; Variables: { uid: string } }>();
// Group HTTP methods for the same resource togetherapp.get("/", ...); // List/Searchapp.get("/:id", ...); // Get singleapp.post("/", ...); // Createapp.put("/:id", ...); // Updateapp.delete("/:id", ...) // DeleteInput Validation
Section titled “Input Validation”- Use zod with
@hono/zod-validatorfor request validation - Define schemas in separate files under
packages/honeygrid-types/schemas/so they can be shared between the API and the frontend - Validate request bodies using
zValidatormiddleware
app.post('/', zValidator('json', ResourceSchema), async (c) => { const validated = c.req.valid('json') // validated is now typed according to schema})Response Format
Section titled “Response Format”- Use
c.json()for JSON responses - Use
c.body(null, 204)for successful deletions - Return appropriate HTTP status codes:
- 200: Success with content
- 201: Resource created
- 204: Success without content
- 400: Bad request
- 404: Not found
- 500: Server error
Error Handling
Section titled “Error Handling”// Bad request exampleif (!workspaceId) { return c.json({ error: 'workspaceId is required' }, 400)}Authentication & Authorization
Section titled “Authentication & Authorization”- Access authenticated user ID via
c.get("uid") - Pass user ID to service methods for authorization
- Always validate resource ownership in services
Service Layer Integration
Section titled “Service Layer Integration”- Use RPC services defined in
rpc-services/ - Access services through
c.env - Keep route handlers thin, business logic belongs in services
const result = await c.env.RESOURCE_SERVICE.someMethod(validated, c.get('uid'))Query Parameters
Section titled “Query Parameters”- Use
c.req.query()for optional parameters - Validate and type query parameters
- Use for filtering, pagination, and sorting
URL Parameters
Section titled “URL Parameters”- Use
c.req.param()for route parameters - Use descriptive parameter names (e.g.,
/:resourceIdnot/:id)
Documentation
Section titled “Documentation”- Add JSDoc comments for each endpoint
- Document expected request/response formats
- Include example requests where helpful
/** * @description Create a new resource * @param {ResourceSchema} body - The resource data * @returns {Promise<Resource>} The created resource */app.post("/", ...);Naming Conventions
Section titled “Naming Conventions”- Use plural nouns for resource endpoints (e.g.,
/connections,/users) - Use kebab-case for multi-word resources
- Use descriptive variable names that indicate content
Middleware
Section titled “Middleware”- Place shared middleware in separate files
- Apply common middleware at the app level
- Use middleware for cross-cutting concerns (logging, metrics, etc.)
Logging
Section titled “Logging”- Cloudflare Workers has observability built into the platform
- Use the
console.logmethod to log messages to the console - Use the
console.errormethod to log errors to the console - If logging a JSON object, use
JSON.stringify(object, null, 2)to log the object with indentation - Add logs to the codebase to help with debugging
- Do not log sensitive information
Testing
Section titled “Testing”- Write tests for each endpoint
- Test happy path and error cases
- Mock service layer calls
- Validate response status codes and bodies