padosoft-hono-api-conventionslisted
Install: claude install-skill padosoft/skills
# Hono API conventions
The conventions that a Hono/Bun API needs applied consistently, and the mistakes that keep coming back. The
goal: an endpoint that goes through review without the same five comments every time.
---
## 1. Three layers, one direction
**Controller → Repository → Query.** Each layer has exactly one job, and the dependency only ever points
downwards.
| Layer | Does | Never does |
|---|---|---|
| **Controller** (`src/controllers/`) | Reads the validated input (`c.req.valid("query"\|"json"\|"param")`), calls the repository, maps relations, returns `c.json(data, status)`, throws `ApiError` | SQL, business transformations |
| **Repository** (`src/repositories/`) | Calls the query, executes it, **transforms** the data, handles caching and transactions | Builds SQL strings, touches the HTTP context |
| **Query** (`src/query/`) | **Only** SQL building. Returns `[sql, params] as const` | Business logic, execution, transformation |
```ts
// src/query/loyalty/query.ts — returns the tuple, executes nothing
export function queryGetLevels(lang: string) {
const sql = `SELECT id, COALESCE(t.descr, b.descr) AS descr
FROM levels b
LEFT JOIN languages l ON l.code = :lang
LEFT JOIN level_languages t ON t.level_ID = b.id AND t.languages_ID = l.id
ORDER BY b.id`;
return [sql, { lang }] as const;
}
// src/repositories/loyalty/repository.ts — executes and transforms
export async function getLevelsRe