Skip to content

Commit 93e002d

Browse files
authored
Merge pull request #233 from jayteemoney/feature/openapi-documentation
feat: #102 Create OpenAPI/Swagger Documentation
2 parents 91e0191 + 4875709 commit 93e002d

File tree

19 files changed

+3941
-1047
lines changed

19 files changed

+3941
-1047
lines changed

backend/docs/API.md

Lines changed: 242 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,242 @@
1+
# Bridge-Watch API Documentation
2+
3+
## Interactive Documentation
4+
5+
Start the backend and open **http://localhost:3000/docs** to access the Swagger UI.
6+
7+
The raw OpenAPI 3.0 JSON spec is served at:
8+
- **http://localhost:3000/api-docs.json** (live, always in sync with code)
9+
- **[backend/docs/openapi.json](./openapi.json)** (checked-in snapshot)
10+
11+
---
12+
13+
## Authentication
14+
15+
Protected endpoints (all `/api/v1/alerts/*` routes and some admin routes) require an API key:
16+
17+
```
18+
x-api-key: <your-api-key>
19+
```
20+
21+
The middleware in `src/api/middleware/auth.ts` validates the key. Without a valid key the server returns `401 Unauthorized`.
22+
23+
---
24+
25+
## Rate Limiting
26+
27+
All endpoints are rate-limited per IP address using a Redis-backed sliding-window algorithm (`src/api/middleware/rateLimit.middleware.ts`). When a limit is exceeded the server responds with:
28+
29+
```
30+
HTTP 429 Too Many Requests
31+
Retry-After: <seconds>
32+
```
33+
34+
Current metrics are available at `GET /api/v1/metrics/rate-limits`.
35+
36+
---
37+
38+
## API Versioning
39+
40+
All REST endpoints are prefixed with `/api/v1/`. When a breaking change is introduced a new version prefix (`/api/v2/`) is added and the previous version is maintained for **at least 90 days** before deprecation.
41+
42+
---
43+
44+
## Error Format
45+
46+
All errors follow a consistent JSON structure:
47+
48+
```json
49+
{
50+
"error": "Short machine-readable label",
51+
"message": "Human-readable description"
52+
}
53+
```
54+
55+
Common HTTP status codes:
56+
57+
| Code | Meaning |
58+
|------|---------|
59+
| 400 | Bad Request — invalid parameters or body |
60+
| 401 | Unauthorized — missing or invalid API key |
61+
| 404 | Not Found |
62+
| 409 | Conflict — e.g. optimistic-lock version mismatch |
63+
| 429 | Too Many Requests |
64+
| 500 | Internal Server Error |
65+
| 501 | Not Implemented |
66+
67+
---
68+
69+
## Endpoint Groups
70+
71+
### Health
72+
| Method | Path | Description |
73+
|--------|------|-------------|
74+
| GET | `/health` | Service health check |
75+
76+
### Assets `/api/v1/assets`
77+
| Method | Path | Description |
78+
|--------|------|-------------|
79+
| GET | `/` | List all monitored assets |
80+
| GET | `/:symbol` | Asset details |
81+
| GET | `/:symbol/health` | Current health score |
82+
| GET | `/:symbol/health/history` | Historical health scores (`period=24h|7d|30d`) |
83+
| GET | `/:symbol/liquidity` | Aggregated liquidity |
84+
| GET | `/:symbol/price` | Aggregated price from all sources |
85+
86+
### Bridges `/api/v1/bridges`
87+
| Method | Path | Description |
88+
|--------|------|-------------|
89+
| GET | `/` | All bridge statuses |
90+
| GET | `/:bridge/stats` | Per-bridge statistics |
91+
92+
### Alerts `/api/v1/alerts` _(requires x-api-key)_
93+
| Method | Path | Description |
94+
|--------|------|-------------|
95+
| GET | `/rules` | List rules for an owner |
96+
| POST | `/rules` | Create a rule |
97+
| GET | `/rules/:ruleId` | Get a single rule |
98+
| PATCH | `/rules/:ruleId` | Update a rule |
99+
| DELETE | `/rules/:ruleId` | Delete a rule |
100+
| PATCH | `/rules/:ruleId/active` | Pause/resume a rule |
101+
| GET | `/rules/:ruleId/events` | Events fired by rule |
102+
| POST | `/rules/bulk` | Bulk create |
103+
| PATCH | `/rules/bulk` | Bulk update |
104+
| DELETE | `/rules/bulk` | Bulk delete |
105+
| GET | `/history` | Paginated alert history |
106+
| GET | `/history/:assetCode` | Asset-scoped history |
107+
| GET | `/stats` | Owner alert statistics |
108+
| GET | `/recent` | Most recent events |
109+
| POST | `/test` | Dry-run a rule |
110+
111+
### Analytics `/api/v1/analytics`
112+
| Method | Path | Description |
113+
|--------|------|-------------|
114+
| GET | `/protocol` | Protocol-wide statistics |
115+
| GET | `/bridges/comparison` | Bridge comparison metrics |
116+
| GET | `/assets/rankings` | Asset rankings |
117+
| GET | `/volume` | Volume aggregations |
118+
| GET | `/trends/:metric` | Metric trend calculation |
119+
| GET | `/top-performers` | Top assets or bridges |
120+
| GET | `/historical/:metric` | Historical comparison |
121+
| GET | `/summary` | Combined analytics summary |
122+
| GET | `/custom-metrics` | List custom metrics |
123+
| GET | `/custom-metrics/:metricId` | Execute a custom metric |
124+
| POST | `/cache/invalidate` | Invalidate analytics cache |
125+
126+
### Aggregation `/api/v1/aggregation`
127+
| Method | Path | Description |
128+
|--------|------|-------------|
129+
| GET | `/:symbol/prices` | OHLCV price aggregation |
130+
| GET | `/:symbol/health` | Health score aggregation |
131+
| GET | `/:symbol/volume` | Volume aggregation |
132+
| GET | `/stats` | Aggregation statistics |
133+
| POST | `/precompute` | Pre-compute for an interval |
134+
| POST | `/rebuild` | Rebuild historical data |
135+
| POST | `/multi-asset` | Multi-asset aggregation |
136+
| POST | `/cache/cleanup` | Remove old cache entries |
137+
138+
### Metadata `/api/v1/metadata`
139+
| Method | Path | Description |
140+
|--------|------|-------------|
141+
| GET | `/` | All asset metadata |
142+
| GET | `/search` | Search metadata |
143+
| GET | `/symbol/:symbol` | By symbol |
144+
| GET | `/category/:category` | By category |
145+
| GET | `/:assetId` | By asset ID |
146+
| GET | `/:assetId/history` | Version history |
147+
| POST | `/` | Create or update |
148+
| PATCH | `/:assetId/logo` | Update logo |
149+
| DELETE | `/:assetId` | Delete |
150+
151+
### Watchlists `/api/v1/watchlists`
152+
| Method | Path | Description |
153+
|--------|------|-------------|
154+
| GET | `/:userId` | User's watchlists |
155+
| POST | `/:userId` | Create watchlist |
156+
| PATCH | `/:userId/:id` | Update watchlist |
157+
| DELETE | `/:userId/:id` | Delete watchlist |
158+
159+
### Preferences `/api/v1/preferences`
160+
| Method | Path | Description |
161+
|--------|------|-------------|
162+
| GET | `/:userId` | All preferences |
163+
| GET | `/:userId/:category/:key` | Single value |
164+
| PUT | `/:userId/:category/:key` | Set single value |
165+
| PATCH | `/:userId/bulk` | Bulk update (optimistic lock) |
166+
| DELETE | `/:userId/:category/:key` | Reset key |
167+
| GET | `/:userId/export` | Export preferences |
168+
| POST | `/:userId/import` | Import preferences |
169+
| GET | `/:userId/stream` | SSE change stream |
170+
171+
### Jobs `/api/v1/jobs`
172+
| Method | Path | Description |
173+
|--------|------|-------------|
174+
| GET | `/monitor` | Queue status and failed jobs |
175+
| POST | `/:jobName/trigger` | Manually enqueue a job |
176+
177+
### Config `/api/v1/config`
178+
| Method | Path | Description |
179+
|--------|------|-------------|
180+
| GET | `/` | All config entries |
181+
| GET | `/:key` | Single entry |
182+
| POST | `/` | Set value |
183+
| DELETE | `/:key` | Delete entry |
184+
| GET | `/features/:name` | Feature flag status |
185+
| POST | `/features` | Set feature flag |
186+
| GET | `/export` | Export config |
187+
| POST | `/import` | Import config |
188+
| GET | `/audit` | Audit trail |
189+
| POST | `/cache/clear` | Clear config cache |
190+
191+
### Cache `/api/v1/cache`
192+
| Method | Path | Description |
193+
|--------|------|-------------|
194+
| GET | `/stats` | Redis cache statistics |
195+
| POST | `/invalidate` | Invalidate by key or tag |
196+
| GET | `/metrics/rate-limits` | Rate-limit metrics |
197+
198+
### Circuit Breaker `/api/v1/circuit-breaker`
199+
| Method | Path | Description |
200+
|--------|------|-------------|
201+
| GET | `/status` | Pause status for a scope |
202+
| GET | `/whitelist` | Whitelist check |
203+
| POST | `/pause` | Pause a scope _(not yet implemented)_ |
204+
| POST | `/recovery` | Recover from pause _(not yet implemented)_ |
205+
206+
---
207+
208+
## Maintenance Guide
209+
210+
### Adding a new endpoint
211+
212+
1. Add the route to the relevant file in `backend/src/api/routes/`.
213+
2. Include a `schema` block with `tags`, `summary`, `params`/`querystring`/`body`, and `response`.
214+
3. If this is a new route file, register it in `backend/src/api/routes/index.ts`.
215+
4. Regenerate the static spec:
216+
```bash
217+
npm run docs:generate
218+
```
219+
5. Commit both the route file and the updated `backend/docs/openapi.json`.
220+
221+
### Updating an existing endpoint
222+
223+
1. Edit the route handler and its inline `schema`.
224+
2. Run `npm run docs:generate` to refresh the static spec.
225+
226+
### Adding a reusable schema component
227+
228+
Add it to the `components.schemas` map in `backend/src/config/openapi.ts`. Reference it in route schemas using `$ref: "SchemaName#"`.
229+
230+
### Validating the spec
231+
232+
Paste `backend/docs/openapi.json` into [https://editor.swagger.io](https://editor.swagger.io) or run:
233+
```bash
234+
npx @stoplight/spectral-cli lint backend/docs/openapi.json
235+
```
236+
237+
### CI integration
238+
239+
The GitHub Actions workflow validates TypeScript compilation (`npm run build`) on every PR. Add a spec-lint step by including:
240+
```yaml
241+
- run: npx @stoplight/spectral-cli lint backend/docs/openapi.json
242+
```

0 commit comments

Comments
 (0)