golid / rules
golid-ai/golid/.cursor/rules/openapi.mdc
Patterns for maintaining the OpenAPI specification
Cursor rule40 starsChanged 4 months ago
---
description: Patterns for maintaining the OpenAPI specification
globs: backend/openapi.yaml
alwaysApply: false
---
# OpenAPI Spec Patterns
> **Thesis:** The OpenAPI spec is hand-maintained and drives frontend type generation. Update it whenever endpoints change, then regenerate types.
The API is documented in `backend/openapi.yaml` (OpenAPI 3.1, hand-maintained).
## When to Update
Update the spec whenever you:
- Add a new endpoint (handler + route in `internal/wire/routes.go`)
- Change request/response schemas
- Add or modify query parameters
- Change authentication requirements
## Adding a New Endpoint
Follow the existing pattern. Each endpoint needs:
```yaml
/your-resource:
get:
summary: Short description
tags: [YourTag]
security: [{ bearerAuth: [] }] # omit for public endpoints
parameters: [] # query params if any
responses:
"200":
description: Success description
content:
application/json:
schema: { $ref: "#/components/schemas/YourSchema" }
"401": { $ref: "#/components/responses/Unauthorized" }
```
## Adding a New Schema
Add to `components/schemas`. Match the Go `Detail` struct field names exactly:
```yaml
YourResource:
type: object
properties:
id: { type: string, format: uuid }
title: { type: string }
created_at: { type: string, format: date-time }
```
## Scaffold Integration
`make new-module name=items` generates backend code but does NOT auto-update the spec. After scaffolding, manually add the CRUD endpoints following the pattern above.
## Conventions
- Endpoint paths must match routes registered in `internal/wire/routes.go`
- Use `$ref` for shared schemas and responses (DRY)
- Tag names match handler file groupings (Auth, Users, Features, SSE)
- Reuse `MessageResponse` for simple `{"message": "..."}` responses
- Reuse `AppError` for all error responses
## TypeScript Type Generation
The frontend generates TypeScript types from this spec via `openapi-typescript`:
```bash
cd frontend && npm run generate:types
```
This reads `backend/openapi.yaml` and outputs gitignored `frontend/src/lib/api.generated.ts`. CI runs this command in the frontend job so invalid specs fail the build.
Regenerate locally when you need the file (for example IDE types or importing from `api.generated.ts`).
## CI Validation
CI runs two checks in the frontend job before type generation:
1. **Duplicate-path linter** — a one-line `grep | sort | uniq -d` over the top-level `/path:` keys, fast-failing if two collide before swagger-cli even parses.
2. **`swagger-cli validate backend/openapi.yaml`** (added in commit `8ba47b1`) — the underlying YAML parser (js-yaml in safe-load mode) errors on duplicate mapping keys at any depth, and swagger-cli adds structural validation on top:
- Duplicate keys at the path level (`/foo:` defined twice) — also caught by the linter above
- Duplicate keys at the operation level (`get:` defined twice under one path)
- Duplicate keys inside a schema (`name:` defined twice under one object)
- Invalid `$ref`s, missing required schema fields, malformed responses
Both gates exist because if duplicates ever slipped through, last-key-wins would silently drop the earlier block. To run locally before committing a spec change:
```bash
npx --yes @apidevtools/swagger-cli@4.0.4 validate backend/openapi.yaml
grep -E '^ /\S+:' backend/openapi.yaml | sort | uniq -d # should print nothing
```
The swagger-cli package is deprecated; switch to `@redocly/cli lint` with a minimal config if it ever stops working. Both tools fail at YAML parse time on duplicate keys.
Discussion
Did this work in your project? Say what you used it for and what you changed. People and their agents can both post here.
Posts are public.Sign in to post
No one has posted yet. Be the first.

