92 lines
2.9 KiB
Markdown
92 lines
2.9 KiB
Markdown
# Contract: REST API Conventions (Go Web Applications)
|
|
|
|
## URL Naming
|
|
|
|
- Resources are plural nouns: `/api/assets`, `/api/components`, `/api/pricelists`.
|
|
- Nested resources use parent path: `/api/assets/:id/components`.
|
|
- Actions that are not CRUD use a verb suffix: `/api/pricelists/:id/export-csv`,
|
|
`/api/tasks/:id/cancel`, `/api/sync/push`.
|
|
- No verbs in resource paths: use `/api/assets` + DELETE, not `/api/delete-asset`.
|
|
|
|
## HTTP Methods and Status Codes
|
|
|
|
| Operation | Method | Success | Notes |
|
|
|-----------|--------|---------|-------|
|
|
| List | GET | 200 | |
|
|
| Get one | GET | 200 / 404 | |
|
|
| Create | POST | 201 | Return created resource |
|
|
| Update | PUT / PATCH | 200 | Return updated resource |
|
|
| Delete / Archive | DELETE | 200 or 204 | |
|
|
| Async action | POST | 202 | Return `{task_id}` |
|
|
| Validation error | POST/PUT | 422 | Return field errors |
|
|
| Server error | any | 500 | Log full error server-side |
|
|
| Not found | any | 404 | |
|
|
| Unauthorized | any | 401 | |
|
|
|
|
- Never return `200 OK` for validation errors — use `422 Unprocessable Entity`.
|
|
- Never return `200 OK` with `{"error": "..."}` in the body — use the correct status code.
|
|
|
|
## Error Response Format
|
|
|
|
All non-2xx responses return a consistent JSON body:
|
|
|
|
```json
|
|
{
|
|
"error": "human-readable message",
|
|
"fields": {
|
|
"serial_number": "Serial number is required",
|
|
"price": "Must be greater than 0"
|
|
}
|
|
}
|
|
```
|
|
|
|
- `error` — always present, describes what went wrong.
|
|
- `fields` — optional, present only for validation errors (422). Keys match form field names.
|
|
- Never expose raw Go error strings, stack traces, or SQL errors to the client.
|
|
|
|
## List Response Format
|
|
|
|
```json
|
|
{
|
|
"items": [...],
|
|
"total_count": 342,
|
|
"page": 2,
|
|
"per_page": 50,
|
|
"total_pages": 7
|
|
}
|
|
```
|
|
|
|
- Always include pagination metadata even if the client did not request it.
|
|
- `items` is always an array — never `null`, use `[]` for empty.
|
|
|
|
## Request Conventions
|
|
|
|
- Accept `application/json` for API endpoints.
|
|
- HTML form submissions (htmx) use `application/x-www-form-urlencoded` or `multipart/form-data`.
|
|
- File uploads use `multipart/form-data`.
|
|
- Query parameters for filtering and pagination: `?page=1&per_page=50&search=abc&status=active`.
|
|
|
|
## Health and Utility Endpoints
|
|
|
|
Every application must expose:
|
|
|
|
```
|
|
GET /health → 200 {"status": "ok"}
|
|
GET /api/db-status → 200 {"ok": true} or 500 {"ok": false, "error": "..."}
|
|
```
|
|
|
|
- `/health` must respond even if DB is down (for load balancer probes).
|
|
- `/api/db-status` checks the actual DB connection and returns its state.
|
|
|
|
## Async Actions
|
|
|
|
For long-running operations return immediately with a task reference:
|
|
|
|
```
|
|
POST /api/pricelists/create → 202 {"task_id": "abc123"}
|
|
GET /api/tasks/abc123 → 200 {"status": "running", "progress": 42, "message": "Processing..."}
|
|
GET /api/tasks/abc123 → 200 {"status": "success", "result": {...}}
|
|
```
|
|
|
|
See `go-background-tasks/contract.md` for full task contract.
|