Skip to content

REST API Style Guide

  • 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
const app = new Hono<{ Bindings: Env; Variables: { uid: string } }>();
// Group HTTP methods for the same resource together
app.get("/", ...); // List/Search
app.get("/:id", ...); // Get single
app.post("/", ...); // Create
app.put("/:id", ...); // Update
app.delete("/:id", ...) // Delete
  • Use zod with @hono/zod-validator for 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 zValidator middleware
app.post('/', zValidator('json', ResourceSchema), async (c) => {
const validated = c.req.valid('json')
// validated is now typed according to schema
})
  • 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
// Bad request example
if (!workspaceId) {
return c.json({ error: 'workspaceId is required' }, 400)
}
  • Access authenticated user ID via c.get("uid")
  • Pass user ID to service methods for authorization
  • Always validate resource ownership in services
  • 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'))
  • Use c.req.query() for optional parameters
  • Validate and type query parameters
  • Use for filtering, pagination, and sorting
  • Use c.req.param() for route parameters
  • Use descriptive parameter names (e.g., /:resourceId not /:id)
  • 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("/", ...);
  • Use plural nouns for resource endpoints (e.g., /connections, /users)
  • Use kebab-case for multi-word resources
  • Use descriptive variable names that indicate content
  • Place shared middleware in separate files
  • Apply common middleware at the app level
  • Use middleware for cross-cutting concerns (logging, metrics, etc.)
  • Cloudflare Workers has observability built into the platform
  • Use the console.log method to log messages to the console
  • Use the console.error method 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
  • Write tests for each endpoint
  • Test happy path and error cases
  • Mock service layer calls
  • Validate response status codes and bodies