Add comprehensive documentation for Quizzical Beats
- Created a detailed database schema document outlining tables, relationships, and key fields. - Added OAuth integration documentation covering Spotify and Dropbox authentication processes. - Introduced a FAQ section addressing common user inquiries about the application. - Developed a user-friendly index page for easy navigation of the documentation. - Specified documentation dependencies in requirements.txt for building the documentation site. - Expanded user guide with sections on account management, creating rounds, exporting rounds, getting started, importing songs, and user interface navigation. - Updated mkdocs.yml for improved site structure and navigation.
This commit is contained in:
@@ -0,0 +1,787 @@
|
||||
# API Reference
|
||||
|
||||
This document provides a comprehensive reference for the Quizzical Beats API endpoints.
|
||||
|
||||
## Authentication
|
||||
|
||||
All API endpoints require authentication unless specified otherwise.
|
||||
|
||||
### Authentication Methods
|
||||
|
||||
The API supports two authentication methods:
|
||||
|
||||
1. **Session Cookie**: For browser-based applications
|
||||
2. **API Key**: For programmatic access
|
||||
|
||||
#### API Key Authentication
|
||||
|
||||
To use API key authentication:
|
||||
|
||||
1. Generate an API key in your profile settings
|
||||
2. Include the key in the `X-API-Key` header with each request:
|
||||
```
|
||||
X-API-Key: your-api-key-here
|
||||
```
|
||||
|
||||
### Rate Limiting
|
||||
|
||||
API requests are rate-limited to prevent abuse:
|
||||
|
||||
- 100 requests per hour for standard users
|
||||
- 300 requests per hour for admin users
|
||||
|
||||
Rate limit headers are included in all responses:
|
||||
```
|
||||
X-RateLimit-Limit: 100
|
||||
X-RateLimit-Remaining: 95
|
||||
X-RateLimit-Reset: 1620567890
|
||||
```
|
||||
|
||||
## Response Format
|
||||
|
||||
All API responses are in JSON format with a consistent structure:
|
||||
|
||||
```json
|
||||
{
|
||||
"status": "success|error",
|
||||
"data": { ... },
|
||||
"message": "Optional message",
|
||||
"pagination": {
|
||||
"page": 1,
|
||||
"per_page": 20,
|
||||
"total": 42,
|
||||
"pages": 3
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Error Handling
|
||||
|
||||
When an error occurs, the response will have status code 4xx or 5xx and include an error message:
|
||||
|
||||
```json
|
||||
{
|
||||
"status": "error",
|
||||
"message": "Descriptive error message",
|
||||
"code": "ERROR_CODE"
|
||||
}
|
||||
```
|
||||
|
||||
Common error codes:
|
||||
- `UNAUTHORIZED`: Authentication failed
|
||||
- `FORBIDDEN`: Permission denied
|
||||
- `NOT_FOUND`: Resource not found
|
||||
- `VALIDATION_ERROR`: Invalid input data
|
||||
- `RATE_LIMITED`: Rate limit exceeded
|
||||
|
||||
## API Endpoints
|
||||
|
||||
### User Endpoints
|
||||
|
||||
#### Get Current User
|
||||
|
||||
```
|
||||
GET /api/user
|
||||
```
|
||||
|
||||
Returns information about the currently authenticated user.
|
||||
|
||||
**Response:**
|
||||
```json
|
||||
{
|
||||
"status": "success",
|
||||
"data": {
|
||||
"id": 123,
|
||||
"username": "john_doe",
|
||||
"email": "john@example.com",
|
||||
"is_admin": false,
|
||||
"created_at": "2025-01-15T12:34:56Z"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### Update User Profile
|
||||
|
||||
```
|
||||
PUT /api/user
|
||||
```
|
||||
|
||||
Update the current user's profile information.
|
||||
|
||||
**Request Body:**
|
||||
```json
|
||||
{
|
||||
"username": "new_username",
|
||||
"email": "new_email@example.com"
|
||||
}
|
||||
```
|
||||
|
||||
**Response:**
|
||||
```json
|
||||
{
|
||||
"status": "success",
|
||||
"data": {
|
||||
"id": 123,
|
||||
"username": "new_username",
|
||||
"email": "new_email@example.com",
|
||||
"is_admin": false,
|
||||
"created_at": "2025-01-15T12:34:56Z"
|
||||
},
|
||||
"message": "Profile updated successfully"
|
||||
}
|
||||
```
|
||||
|
||||
### Song Endpoints
|
||||
|
||||
#### List Songs
|
||||
|
||||
```
|
||||
GET /api/songs
|
||||
```
|
||||
|
||||
Returns a paginated list of songs in the user's library.
|
||||
|
||||
**Query Parameters:**
|
||||
- `page`: Page number (default: 1)
|
||||
- `per_page`: Items per page (default: 20, max: 100)
|
||||
- `search`: Search term
|
||||
- `sort`: Sort field (title, artist, album, year)
|
||||
- `order`: Sort order (asc, desc)
|
||||
- `genre`: Filter by genre
|
||||
- `year`: Filter by year
|
||||
|
||||
**Response:**
|
||||
```json
|
||||
{
|
||||
"status": "success",
|
||||
"data": [
|
||||
{
|
||||
"id": 456,
|
||||
"title": "Song Title",
|
||||
"artist": "Artist Name",
|
||||
"album": "Album Name",
|
||||
"year": 2010,
|
||||
"genre": "Rock",
|
||||
"preview_url": "https://example.com/preview.mp3",
|
||||
"spotify_id": "spotify:track:abcdef123456",
|
||||
"duration_ms": 240000
|
||||
},
|
||||
// More songs...
|
||||
],
|
||||
"pagination": {
|
||||
"page": 1,
|
||||
"per_page": 20,
|
||||
"total": 42,
|
||||
"pages": 3
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### Get Song
|
||||
|
||||
```
|
||||
GET /api/songs/{id}
|
||||
```
|
||||
|
||||
Returns detailed information about a specific song.
|
||||
|
||||
**Response:**
|
||||
```json
|
||||
{
|
||||
"status": "success",
|
||||
"data": {
|
||||
"id": 456,
|
||||
"title": "Song Title",
|
||||
"artist": "Artist Name",
|
||||
"album": "Album Name",
|
||||
"year": 2010,
|
||||
"genre": "Rock",
|
||||
"preview_url": "https://example.com/preview.mp3",
|
||||
"spotify_id": "spotify:track:abcdef123456",
|
||||
"duration_ms": 240000,
|
||||
"added_by": 123,
|
||||
"created_at": "2025-02-10T15:30:45Z",
|
||||
"popularity": 75,
|
||||
"tags": [
|
||||
{
|
||||
"id": 789,
|
||||
"name": "Summer Hits",
|
||||
"color": "#ff5500"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### Create Song
|
||||
|
||||
```
|
||||
POST /api/songs
|
||||
```
|
||||
|
||||
Add a new song to the user's library.
|
||||
|
||||
**Request Body:**
|
||||
```json
|
||||
{
|
||||
"title": "New Song",
|
||||
"artist": "New Artist",
|
||||
"album": "New Album",
|
||||
"year": 2025,
|
||||
"genre": "Pop",
|
||||
"spotify_id": "spotify:track:xyz789",
|
||||
"preview_url": "https://example.com/preview.mp3"
|
||||
}
|
||||
```
|
||||
|
||||
**Response:**
|
||||
```json
|
||||
{
|
||||
"status": "success",
|
||||
"data": {
|
||||
"id": 457,
|
||||
"title": "New Song",
|
||||
"artist": "New Artist",
|
||||
"album": "New Album",
|
||||
"year": 2025,
|
||||
"genre": "Pop",
|
||||
"preview_url": "https://example.com/preview.mp3",
|
||||
"spotify_id": "spotify:track:xyz789",
|
||||
"added_by": 123,
|
||||
"created_at": "2025-05-11T09:12:34Z"
|
||||
},
|
||||
"message": "Song added successfully"
|
||||
}
|
||||
```
|
||||
|
||||
#### Update Song
|
||||
|
||||
```
|
||||
PUT /api/songs/{id}
|
||||
```
|
||||
|
||||
Update an existing song.
|
||||
|
||||
**Request Body:**
|
||||
```json
|
||||
{
|
||||
"title": "Updated Title",
|
||||
"artist": "Updated Artist",
|
||||
"album": "Updated Album",
|
||||
"year": 2020,
|
||||
"genre": "Electronic"
|
||||
}
|
||||
```
|
||||
|
||||
**Response:**
|
||||
```json
|
||||
{
|
||||
"status": "success",
|
||||
"data": {
|
||||
"id": 456,
|
||||
"title": "Updated Title",
|
||||
"artist": "Updated Artist",
|
||||
"album": "Updated Album",
|
||||
"year": 2020,
|
||||
"genre": "Electronic",
|
||||
"preview_url": "https://example.com/preview.mp3",
|
||||
"spotify_id": "spotify:track:abcdef123456"
|
||||
},
|
||||
"message": "Song updated successfully"
|
||||
}
|
||||
```
|
||||
|
||||
#### Delete Song
|
||||
|
||||
```
|
||||
DELETE /api/songs/{id}
|
||||
```
|
||||
|
||||
Remove a song from the user's library.
|
||||
|
||||
**Response:**
|
||||
```json
|
||||
{
|
||||
"status": "success",
|
||||
"message": "Song deleted successfully"
|
||||
}
|
||||
```
|
||||
|
||||
### Round Endpoints
|
||||
|
||||
#### List Rounds
|
||||
|
||||
```
|
||||
GET /api/rounds
|
||||
```
|
||||
|
||||
Returns a paginated list of the user's quiz rounds.
|
||||
|
||||
**Query Parameters:**
|
||||
- `page`: Page number (default: 1)
|
||||
- `per_page`: Items per page (default: 20, max: 100)
|
||||
- `search`: Search term
|
||||
- `sort`: Sort field (name, created_at)
|
||||
- `order`: Sort order (asc, desc)
|
||||
- `tag`: Filter by tag ID
|
||||
|
||||
**Response:**
|
||||
```json
|
||||
{
|
||||
"status": "success",
|
||||
"data": [
|
||||
{
|
||||
"id": 789,
|
||||
"name": "80s Rock Classics",
|
||||
"description": "Classic rock hits from the 1980s",
|
||||
"created_at": "2025-03-20T14:25:36Z",
|
||||
"song_count": 10,
|
||||
"round_type": "decade",
|
||||
"tags": [
|
||||
{
|
||||
"id": 123,
|
||||
"name": "80s",
|
||||
"color": "#3366ff"
|
||||
},
|
||||
{
|
||||
"id": 456,
|
||||
"name": "Rock",
|
||||
"color": "#cc0000"
|
||||
}
|
||||
]
|
||||
},
|
||||
// More rounds...
|
||||
],
|
||||
"pagination": {
|
||||
"page": 1,
|
||||
"per_page": 20,
|
||||
"total": 15,
|
||||
"pages": 1
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### Get Round
|
||||
|
||||
```
|
||||
GET /api/rounds/{id}
|
||||
```
|
||||
|
||||
Returns detailed information about a specific round, including its songs.
|
||||
|
||||
**Response:**
|
||||
```json
|
||||
{
|
||||
"status": "success",
|
||||
"data": {
|
||||
"id": 789,
|
||||
"name": "80s Rock Classics",
|
||||
"description": "Classic rock hits from the 1980s",
|
||||
"created_at": "2025-03-20T14:25:36Z",
|
||||
"user_id": 123,
|
||||
"is_public": true,
|
||||
"round_type": "decade",
|
||||
"intro_file": "/mp3/intros/80s_intro.mp3",
|
||||
"outro_file": "/mp3/outros/rock_outro.mp3",
|
||||
"songs": [
|
||||
{
|
||||
"id": 101,
|
||||
"title": "Sweet Child O' Mine",
|
||||
"artist": "Guns N' Roses",
|
||||
"year": 1987,
|
||||
"position": 1,
|
||||
"question": "Name this iconic 80s rock song",
|
||||
"answer": "Sweet Child O' Mine by Guns N' Roses",
|
||||
"points": 10,
|
||||
"preview_url": "https://example.com/preview1.mp3"
|
||||
},
|
||||
// More songs...
|
||||
],
|
||||
"tags": [
|
||||
{
|
||||
"id": 123,
|
||||
"name": "80s",
|
||||
"color": "#3366ff"
|
||||
},
|
||||
{
|
||||
"id": 456,
|
||||
"name": "Rock",
|
||||
"color": "#cc0000"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### Create Round
|
||||
|
||||
```
|
||||
POST /api/rounds
|
||||
```
|
||||
|
||||
Create a new quiz round.
|
||||
|
||||
**Request Body:**
|
||||
```json
|
||||
{
|
||||
"name": "New Quiz Round",
|
||||
"description": "A fresh music quiz round",
|
||||
"round_type": "mixed",
|
||||
"is_public": true,
|
||||
"song_ids": [101, 102, 103, 104],
|
||||
"tag_ids": [123, 456]
|
||||
}
|
||||
```
|
||||
|
||||
**Response:**
|
||||
```json
|
||||
{
|
||||
"status": "success",
|
||||
"data": {
|
||||
"id": 790,
|
||||
"name": "New Quiz Round",
|
||||
"description": "A fresh music quiz round",
|
||||
"created_at": "2025-05-11T10:15:20Z",
|
||||
"user_id": 123,
|
||||
"is_public": true,
|
||||
"round_type": "mixed",
|
||||
"song_count": 4
|
||||
},
|
||||
"message": "Round created successfully"
|
||||
}
|
||||
```
|
||||
|
||||
#### Update Round
|
||||
|
||||
```
|
||||
PUT /api/rounds/{id}
|
||||
```
|
||||
|
||||
Update an existing round.
|
||||
|
||||
**Request Body:**
|
||||
```json
|
||||
{
|
||||
"name": "Updated Round Name",
|
||||
"description": "Updated description",
|
||||
"is_public": false,
|
||||
"song_ids": [101, 102, 105, 106],
|
||||
"tag_ids": [123, 789]
|
||||
}
|
||||
```
|
||||
|
||||
**Response:**
|
||||
```json
|
||||
{
|
||||
"status": "success",
|
||||
"data": {
|
||||
"id": 789,
|
||||
"name": "Updated Round Name",
|
||||
"description": "Updated description",
|
||||
"is_public": false,
|
||||
"song_count": 4
|
||||
},
|
||||
"message": "Round updated successfully"
|
||||
}
|
||||
```
|
||||
|
||||
#### Delete Round
|
||||
|
||||
```
|
||||
DELETE /api/rounds/{id}
|
||||
```
|
||||
|
||||
Delete a quiz round.
|
||||
|
||||
**Response:**
|
||||
```json
|
||||
{
|
||||
"status": "success",
|
||||
"message": "Round deleted successfully"
|
||||
}
|
||||
```
|
||||
|
||||
### Export Endpoints
|
||||
|
||||
#### Export Round to Dropbox
|
||||
|
||||
```
|
||||
POST /rounds/{round_id}/export-to-dropbox
|
||||
```
|
||||
|
||||
Export a round to the user's connected Dropbox account.
|
||||
|
||||
**Request Body Parameters:**
|
||||
```
|
||||
include_mp3s: boolean (default: true) - Whether to include MP3 files in the export
|
||||
include_pdf: boolean (default: true) - Whether to include PDF in the export
|
||||
custom_folder: string (optional) - Additional subfolder path within the user's configured export path
|
||||
```
|
||||
|
||||
**Response:**
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"message": "Round exported to Dropbox successfully",
|
||||
"shared_links": {
|
||||
"text": "https://www.dropbox.com/s/abc123/round_123_metadata.json?dl=0",
|
||||
"pdf": "https://www.dropbox.com/s/def456/round_123.pdf?dl=0",
|
||||
"mp3": "https://www.dropbox.com/s/ghi789/round_123.mp3?dl=0"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Error Response:**
|
||||
```json
|
||||
{
|
||||
"success": false,
|
||||
"message": "Error exporting to Dropbox: <error details>",
|
||||
"redirect": "URL for MP3 generation if needed"
|
||||
}
|
||||
```
|
||||
|
||||
#### List Dropbox Folders
|
||||
|
||||
```
|
||||
GET /api/dropbox/folders
|
||||
```
|
||||
|
||||
List folders from the user's Dropbox account.
|
||||
|
||||
**Query Parameters:**
|
||||
```
|
||||
path: string - The path to list folders from (default: root)
|
||||
```
|
||||
|
||||
**Response:**
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"folders": [
|
||||
{
|
||||
"name": "Folder Name",
|
||||
"path": "/Folder Name",
|
||||
"is_dir": true
|
||||
},
|
||||
{
|
||||
"name": "Documents",
|
||||
"path": "/Documents",
|
||||
"is_dir": true
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
#### Create Dropbox Folder
|
||||
|
||||
```
|
||||
POST /api/dropbox/create-folder
|
||||
```
|
||||
|
||||
Create a new folder in the user's Dropbox account.
|
||||
|
||||
**Request Body:**
|
||||
```json
|
||||
{
|
||||
"parent_path": "/path/to/parent",
|
||||
"folder_name": "New Folder"
|
||||
}
|
||||
```
|
||||
|
||||
**Response:**
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"message": "Folder created successfully",
|
||||
"folder": {
|
||||
"name": "New Folder",
|
||||
"path": "/path/to/parent/New Folder",
|
||||
"is_dir": true
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Dropbox OAuth Endpoints
|
||||
|
||||
#### Connect Dropbox Account
|
||||
|
||||
```
|
||||
GET /users/dropbox/connect
|
||||
```
|
||||
|
||||
Initiates the OAuth flow for connecting a Dropbox account.
|
||||
|
||||
**Response:**
|
||||
Redirects to Dropbox OAuth authorization page
|
||||
|
||||
#### Dropbox OAuth Callback
|
||||
|
||||
```
|
||||
GET /users/dropbox/callback
|
||||
```
|
||||
|
||||
Handles the OAuth callback from Dropbox.
|
||||
|
||||
**Query Parameters:**
|
||||
```
|
||||
code: string - The authorization code from Dropbox
|
||||
error: string - Error message if authorization failed
|
||||
```
|
||||
|
||||
**Response:**
|
||||
Redirects back to user profile page with a success or error message
|
||||
|
||||
#### Disconnect Dropbox Account
|
||||
|
||||
```
|
||||
POST /users/dropbox/disconnect
|
||||
```
|
||||
|
||||
Disconnects the user's Dropbox account.
|
||||
|
||||
**Response:**
|
||||
Redirects back to user profile page with a success message
|
||||
|
||||
### Spotify Integration Endpoints
|
||||
|
||||
#### Get User Playlists
|
||||
|
||||
```
|
||||
GET /api/spotify/playlists
|
||||
```
|
||||
|
||||
Get the current user's Spotify playlists.
|
||||
|
||||
**Response:**
|
||||
```json
|
||||
{
|
||||
"status": "success",
|
||||
"data": [
|
||||
{
|
||||
"id": "spotify:playlist:abcdef123456",
|
||||
"name": "My Awesome Playlist",
|
||||
"owner": "spotify_user123",
|
||||
"track_count": 42,
|
||||
"image_url": "https://example.com/playlist_cover.jpg"
|
||||
},
|
||||
// More playlists...
|
||||
],
|
||||
"pagination": {
|
||||
"page": 1,
|
||||
"per_page": 20,
|
||||
"total": 35,
|
||||
"pages": 2
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### Import Playlist
|
||||
|
||||
```
|
||||
POST /api/spotify/import/playlist
|
||||
```
|
||||
|
||||
Import songs from a Spotify playlist.
|
||||
|
||||
**Request Body:**
|
||||
```json
|
||||
{
|
||||
"playlist_id": "spotify:playlist:abcdef123456",
|
||||
"limit": 20
|
||||
}
|
||||
```
|
||||
|
||||
**Response:**
|
||||
```json
|
||||
{
|
||||
"status": "success",
|
||||
"data": {
|
||||
"import_id": "imp_789012",
|
||||
"playlist_name": "My Awesome Playlist",
|
||||
"status": "processing",
|
||||
"songs_found": 42,
|
||||
"songs_to_import": 20,
|
||||
"estimated_completion": "45 seconds"
|
||||
},
|
||||
"message": "Import started"
|
||||
}
|
||||
```
|
||||
|
||||
### Health Check Endpoint
|
||||
|
||||
```
|
||||
GET /api/health
|
||||
```
|
||||
|
||||
Get system health information (admin only).
|
||||
|
||||
**Response:**
|
||||
```json
|
||||
{
|
||||
"status": "success",
|
||||
"data": {
|
||||
"version": "1.0.0",
|
||||
"uptime": "5d 12h 37m",
|
||||
"database": {
|
||||
"status": "connected",
|
||||
"size": "42MB",
|
||||
"migrations": "up-to-date"
|
||||
},
|
||||
"storage": {
|
||||
"available": "1.2GB",
|
||||
"used": "345MB"
|
||||
},
|
||||
"services": {
|
||||
"spotify": "connected",
|
||||
"dropbox": "connected",
|
||||
"email": "connected"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Webhook Notifications
|
||||
|
||||
Quizzical Beats can send webhook notifications for certain events.
|
||||
|
||||
### Configuring Webhooks
|
||||
|
||||
Webhooks are configured in the admin settings:
|
||||
|
||||
1. Go to Admin > System > Webhooks
|
||||
2. Add a new webhook URL
|
||||
3. Select which events to receive notifications for
|
||||
|
||||
### Webhook Events
|
||||
|
||||
- `round.created`: A new round was created
|
||||
- `round.exported`: A round was exported
|
||||
- `import.completed`: A Spotify import was completed
|
||||
- `backup.completed`: A system backup was completed
|
||||
|
||||
### Webhook Payload
|
||||
|
||||
```json
|
||||
{
|
||||
"event": "round.exported",
|
||||
"timestamp": "2025-05-11T10:30:45Z",
|
||||
"data": {
|
||||
"round_id": 789,
|
||||
"round_name": "80s Rock Classics",
|
||||
"user_id": 123,
|
||||
"username": "john_doe",
|
||||
"export_format": "zip",
|
||||
"destination": "dropbox"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## API Versioning
|
||||
|
||||
The current API version is v1. The version is specified in the URL path:
|
||||
|
||||
```
|
||||
/api/v1/resource
|
||||
```
|
||||
|
||||
For backward compatibility, requests to `/api/resource` will be directed to the latest stable API version.
|
||||
Reference in New Issue
Block a user