From 6b68a91f2bec7c56df8c0d5071e369a53eda6b2e Mon Sep 17 00:00:00 2001 From: Arpita Date: Sun, 28 Jun 2026 14:21:35 +0530 Subject: [PATCH] docs: improve API documentation and OpenAPI specification --- docs/api.md | 219 +++++++++++++++++++++++ public/openapi.yaml | 423 +++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 641 insertions(+), 1 deletion(-) diff --git a/docs/api.md b/docs/api.md index d929a28ed..405692c56 100644 --- a/docs/api.md +++ b/docs/api.md @@ -444,3 +444,222 @@ When adding or modifying API routes: 4. Update this document if a new API category or major endpoint group is introduced. Keeping these resources synchronized ensures contributors, self-hosters, and integrators always have accurate API documentation. + +--- + +## Error Responses + +### Common Error Codes + +| Status Code | Description | Troubleshooting | +|-------------|-------------|----------------| +| `400 Bad Request` | Invalid request parameters or malformed JSON | Check request body format and required fields | +| `401 Unauthorized` | Missing or invalid authentication | Ensure session cookie is present and valid | +| `403 Forbidden` | Insufficient permissions for the requested resource | Verify user has access to the requested resource | +| `404 Not Found` | Resource does not exist | Check endpoint URL and resource identifiers | +| `409 Conflict` | Resource already exists or state conflict | Review current state before retrying | +| `422 Validation Error` | Request validation failed | Check field constraints and data types | +| `429 Too Many Requests` | Rate limit exceeded | Wait before retrying or implement exponential backoff | +| `500 Internal Server Error` | Server error | Check server logs and contact support if persistent | + +### Error Response Format + +All error responses follow this format: + +```json +{ + "error": "Error message describing what went wrong" +} +``` + +### Rate Limiting + +Some endpoints have rate limits to prevent abuse: + +- **Leaderboard API**: 20 requests per minute per IP address +- **Public Profile API**: Rate limited to prevent abuse +- **GitHub API**: Inherits GitHub's rate limits (5,000 req/hr authenticated, 60 req/hr unauthenticated) + +Rate limit responses include appropriate headers and status codes. + +--- + +## Code Examples + +### Authentication + +Most endpoints require authentication via NextAuth session cookies. For programmatic access, you'll need to authenticate first. + +#### JavaScript (Fetch) + +```javascript +// Example: Get user goals +async function getGoals() { + const response = await fetch('https://devtrack.vercel.app/api/goals', { + method: 'GET', + credentials: 'include', // Include cookies for authentication + headers: { + 'Content-Type': 'application/json', + }, + }); + + if (!response.ok) { + throw new Error(`HTTP error! status: ${response.status}`); + } + + const data = await response.json(); + return data; +} +``` + +#### Python (Requests) + +```python +import requests + +# Example: Get user goals +def get_goals(): + response = requests.get( + 'https://devtrack.vercel.app/api/goals', + cookies={'next-auth.session-token': 'your-session-token'} + ) + + if response.status_code != 200: + raise Exception(f'HTTP error! status: {response.status_code}') + + return response.json() +``` + +#### cURL + +```bash +# Example: Get user goals +curl -X GET 'https://devtrack.vercel.app/api/goals' \ + -H 'Content-Type: application/json' \ + --cookie 'next-auth.session-token=your-session-token' +``` + +### Goals API Examples + +#### Create a Goal + +**JavaScript:** +```javascript +async function createGoal(title, target, unit) { + const response = await fetch('https://devtrack.vercel.app/api/goals', { + method: 'POST', + credentials: 'include', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ + title: title, + target: target, + unit: unit + }), + }); + + return response.json(); +} +``` + +**Python:** +```python +def create_goal(title, target, unit): + response = requests.post( + 'https://devtrack.vercel.app/api/goals', + cookies={'next-auth.session-token': 'your-session-token'}, + json={ + 'title': title, + 'target': target, + 'unit': unit + } + ) + return response.json() +``` + +**cURL:** +```bash +curl -X POST 'https://devtrack.vercel.app/api/goals' \ + -H 'Content-Type: application/json' \ + --cookie 'next-auth.session-token=your-session-token' \ + -d '{ + "title": "Weekly Commits", + "target": 20, + "unit": "commits" + }' +``` + +### Metrics API Examples + +#### Get Contribution Data + +**JavaScript:** +```javascript +async function getContributions(days = 30) { + const response = await fetch( + `https://devtrack.vercel.app/api/metrics/contributions?days=${days}`, + { + method: 'GET', + credentials: 'include', + } + ); + + return response.json(); +} +``` + +**Python:** +```python +def get_contributions(days=30): + response = requests.get( + f'https://devtrack.vercel.app/api/metrics/contributions?days={days}', + cookies={'next-auth.session-token': 'your-session-token'} + ) + return response.json() +``` + +**cURL:** +```bash +curl -X GET 'https://devtrack.vercel.app/api/metrics/contributions?days=30' \ + --cookie 'next-auth.session-token=your-session-token' +``` + +### Public Profile API Examples + +#### Get Public Profile + +**JavaScript:** +```javascript +async function getPublicProfile(username) { + const response = await fetch( + `https://devtrack.vercel.app/api/public/${username}`, + { + method: 'GET', + } + ); + + if (response.status === 404) { + throw new Error('User not found or profile is private'); + } + + return response.json(); +} +``` + +**Python:** +```python +def get_public_profile(username): + response = requests.get( + f'https://devtrack.vercel.app/api/public/{username}' + ) + + if response.status_code == 404: + raise Exception('User not found or profile is private') + + return response.json() +``` + +**cURL:** +```bash +curl -X GET 'https://devtrack.vercel.app/api/public/username' diff --git a/public/openapi.yaml b/public/openapi.yaml index 52b2df79f..01f56c03f 100644 --- a/public/openapi.yaml +++ b/public/openapi.yaml @@ -527,4 +527,425 @@ paths: '401': description: Unauthorized '404': - description: Account not found \ No newline at end of file + description: Account not found + + # NOTIFICATIONS ROUTES + /api/notifications: + get: + tags: [Notifications] + summary: Get recent notifications + security: + - cookieAuth: [] + responses: + '200': + description: List of notifications + content: + application/json: + schema: + type: object + properties: + notifications: + type: array + items: + type: object + properties: + id: + type: string + type: + type: string + message: + type: string + read: + type: boolean + created_at: + type: string + format: date-time + unreadCount: + type: number + '401': + description: Unauthorized + patch: + tags: [Notifications] + summary: Mark all notifications as read + security: + - cookieAuth: [] + responses: + '200': + description: All notifications marked as read + '401': + description: Unauthorized + + /api/notifications/{id}: + patch: + tags: [Notifications] + summary: Mark a specific notification as read + security: + - cookieAuth: [] + parameters: + - name: id + in: path + required: true + schema: + type: string + responses: + '200': + description: Notification marked as read + '401': + description: Unauthorized + '404': + description: Notification not found + + # LEADERBOARD ROUTES + /api/leaderboard: + get: + tags: [Leaderboard] + summary: Get public leaderboard rankings + parameters: + - name: lang + in: query + required: false + schema: + type: string + description: Filter by primary language + - name: period + in: query + required: false + schema: + type: string + enum: [week, month, year] + description: Filter by time period + responses: + '200': + description: Leaderboard data + content: + application/json: + schema: + type: object + '429': + description: Rate limit exceeded + + /api/leaderboard/refresh: + post: + tags: [Leaderboard] + summary: Trigger leaderboard refresh + responses: + '200': + description: Leaderboard refresh triggered + + /api/leaderboard/rebuild: + post: + tags: [Leaderboard] + summary: Full leaderboard rebuild + security: + - bearerAuth: [] + parameters: + - name: Authorization + in: header + required: true + schema: + type: string + description: Bearer token with LEADERBOARD_REBUILD_TOKEN + responses: + '200': + description: Leaderboard rebuild started + '401': + description: Invalid or missing rebuild token + + # PUBLIC PROFILE ROUTES + /api/public/{username}: + get: + tags: [Public] + summary: Get public profile data for a user + parameters: + - name: username + in: path + required: true + schema: + type: string + responses: + '200': + description: Public profile data + content: + application/json: + schema: + type: object + '404': + description: User not found or profile is private + + /api/public/privacy: + get: + tags: [Public] + summary: Get current user's privacy settings + security: + - cookieAuth: [] + responses: + '200': + description: Privacy settings + content: + application/json: + schema: + type: object + '401': + description: Unauthorized + patch: + tags: [Public] + summary: Update privacy settings + security: + - cookieAuth: [] + requestBody: + required: true + content: + application/json: + schema: + type: object + responses: + '200': + description: Privacy settings updated + '401': + description: Unauthorized + + # WEBHOOK ROUTES + /api/webhooks/github: + post: + tags: [Webhooks] + summary: Receive GitHub push events + parameters: + - name: x-hub-signature-256 + in: header + required: true + schema: + type: string + description: GitHub webhook signature + - name: x-github-event + in: header + required: true + schema: + type: string + description: GitHub event type + requestBody: + required: true + content: + application/json: + schema: + type: object + responses: + '200': + description: Webhook processed successfully + '401': + description: Invalid signature + '400': + description: Bad request + + /api/webhooks/custom: + get: + tags: [Webhooks] + summary: List user's configured webhooks + security: + - cookieAuth: [] + responses: + '200': + description: List of webhooks + content: + application/json: + schema: + type: array + items: + type: object + '401': + description: Unauthorized + post: + tags: [Webhooks] + summary: Create a new webhook + security: + - cookieAuth: [] + requestBody: + required: true + content: + application/json: + schema: + type: object + required: [url] + properties: + url: + type: string + format: uri + events: + type: array + items: + type: string + responses: + '201': + description: Webhook created + '401': + description: Unauthorized + '400': + description: Invalid URL or configuration + + /api/webhooks/custom/{id}: + get: + tags: [Webhooks] + summary: Get webhook details + security: + - cookieAuth: [] + parameters: + - name: id + in: path + required: true + schema: + type: string + responses: + '200': + description: Webhook details + '401': + description: Unauthorized + '404': + description: Webhook not found + patch: + tags: [Webhooks] + summary: Update a webhook + security: + - cookieAuth: [] + parameters: + - name: id + in: path + required: true + schema: + type: string + requestBody: + required: true + content: + application/json: + schema: + type: object + responses: + '200': + description: Webhook updated + '401': + description: Unauthorized + '404': + description: Webhook not found + delete: + tags: [Webhooks] + summary: Delete a webhook + security: + - cookieAuth: [] + parameters: + - name: id + in: path + required: true + schema: + type: string + responses: + '200': + description: Webhook deleted + '401': + description: Unauthorized + '404': + description: Webhook not found + + # AI FEATURES + /api/ai/roast: + post: + tags: [AI] + summary: Generate AI roast or hype of coding style + security: + - cookieAuth: [] + requestBody: + required: true + content: + application/json: + schema: + type: object + responses: + '200': + description: AI-generated content + content: + application/json: + schema: + type: object + '401': + description: Unauthorized + '500': + description: AI service unavailable (GROQ_API_KEY not configured) + + /api/ai/weekly-summary: + post: + tags: [AI] + summary: Generate AI weekly summary + security: + - cookieAuth: [] + requestBody: + required: true + content: + application/json: + schema: + type: object + responses: + '200': + description: AI-generated weekly summary + content: + application/json: + schema: + type: object + '401': + description: Unauthorized + + # WAKATIME INTEGRATION + /api/wakatime: + get: + tags: [Integrations] + summary: Get WakaTime connection status + security: + - cookieAuth: [] + responses: + '200': + description: WakaTime connection status + content: + application/json: + schema: + type: object + '401': + description: Unauthorized + delete: + tags: [Integrations] + summary: Disconnect WakaTime + security: + - cookieAuth: [] + responses: + '200': + description: WakaTime disconnected + '401': + description: Unauthorized + + /api/wakatime/sync: + post: + tags: [Integrations] + summary: Trigger WakaTime data sync + security: + - cookieAuth: [] + responses: + '200': + description: WakaTime sync triggered + '401': + description: Unauthorized + '429': + description: Rate limit exceeded + + # STREAK FREEZE + /api/streak/freeze: + post: + tags: [Streak] + summary: Use a streak freeze to protect current streak + security: + - cookieAuth: [] + responses: + '200': + description: Streak freeze applied + content: + application/json: + schema: + type: object + '401': + description: Unauthorized + '400': + description: No streak freezes available \ No newline at end of file