- Centralize API endpoints in dedicated api app with v1 versioning - Remove individual API modules from parks and rides apps - Add event tracking system with analytics functionality - Integrate Vue.js frontend with Tailwind CSS v4 and TypeScript - Add comprehensive database migrations for event tracking - Implement user authentication and social provider setup - Add API schema documentation and serializers - Configure development environment with shared scripts - Update project structure for monorepo with frontend/backend separation
13 KiB
ThrillWiki API Documentation
Complete API reference for the ThrillWiki Django REST API backend.
Overview
The ThrillWiki API provides comprehensive access to theme park and roller coaster data through a RESTful interface designed specifically for the Vue.js frontend. The API uses Django REST Framework with custom frontend-compatible serializers that convert Django's snake_case to JavaScript's camelCase convention.
Base URL: http://localhost:8000/api/
Authentication
The API currently supports anonymous access for read operations. Authentication will be added in future versions for write operations and user-specific features.
API Endpoints
Parks
List Parks
GET /api/parks/
Response Format:
{
"count": 150,
"next": "http://localhost:8000/api/parks/?page=2",
"previous": null,
"results": [
{
"id": 1,
"name": "Cedar Point",
"slug": "cedar-point",
"location": "Sandusky, Ohio",
"operator": "Cedar Fair",
"openingYear": 1870,
"status": "open",
"description": "America's Roller Coast",
"website": "https://www.cedarpoint.com",
"imageUrl": "/placeholder-park.jpg"
}
]
}
Query Parameters:
page- Page number for paginationsearch- Search parks by name or locationstatus- Filter by park status (open,closed,seasonal)operator- Filter by operator name
Get Park Details
GET /api/parks/{id}/
Response Format:
{
"id": 1,
"name": "Cedar Point",
"slug": "cedar-point",
"location": "Sandusky, Ohio",
"operator": "Cedar Fair",
"openingYear": 1870,
"status": "open",
"description": "America's Roller Coast",
"website": "https://www.cedarpoint.com",
"imageUrl": "/placeholder-park.jpg",
"averageRating": 4.5,
"rideCount": 72,
"coasterCount": 17,
"sizeAcres": 364,
"operatingSeason": "May-October"
}
Rides
List Rides
GET /api/rides/
Response Format:
{
"count": 500,
"next": "http://localhost:8000/api/rides/?page=2",
"previous": null,
"results": [
{
"id": 1,
"name": "Millennium Force",
"slug": "millennium-force",
"parkId": 1,
"parkName": "Cedar Point",
"parkSlug": "cedar-point",
"category": "roller_coaster",
"manufacturer": "Intamin",
"designer": "Werner Stengel",
"openingYear": 2000,
"height": 310,
"speed": 93,
"length": 6595,
"inversions": 0,
"status": "operating",
"description": "World's tallest complete-circuit roller coaster",
"imageUrl": "/placeholder-ride.jpg",
"thrillLevel": "extreme"
}
]
}
Query Parameters:
page- Page number for paginationsearch- Search rides by namepark- Filter by park IDcategory- Filter by ride category (roller_coaster,dark_ride,flat_ride,water_ride,transport,other)status- Filter by ride status (operating,closed,sbno,under_construction)manufacturer- Filter by manufacturer namethrill_level- Filter by thrill level (family,moderate,intense,extreme)
Get Ride Details
GET /api/rides/{id}/
Response Format:
{
"id": 1,
"name": "Millennium Force",
"slug": "millennium-force",
"parkId": 1,
"parkName": "Cedar Point",
"parkSlug": "cedar-point",
"category": "roller_coaster",
"manufacturer": "Intamin",
"designer": "Werner Stengel",
"openingYear": 2000,
"height": 310,
"speed": 93,
"length": 6595,
"inversions": 0,
"status": "operating",
"description": "World's tallest complete-circuit roller coaster",
"imageUrl": "/placeholder-ride.jpg",
"thrillLevel": "extreme",
"minHeightIn": 48,
"maxHeightIn": 78,
"capacityPerHour": 1300,
"rideDurationSeconds": 120,
"averageRating": 4.8,
"closingDate": null,
"statusSince": "2000-05-13",
"coasterStats": {
"trackMaterial": "steel",
"coasterType": "hypercoaster",
"launchType": "chain_lift",
"maxDropHeightFt": 300,
"rideTimeSeconds": 120,
"trainsCount": 2,
"carsPerTrain": 9,
"seatsPerCar": 4,
"trainStyle": "open_air",
"trackType": "complete_circuit"
}
}
Get Rides by Park
GET /api/parks/{park_id}/rides/
Returns all rides for a specific park using the same format as the main rides endpoint.
Data Models
Park Data Structure
| Field | Type | Description |
|---|---|---|
id |
integer | Unique park identifier |
name |
string | Park name |
slug |
string | URL-friendly park identifier |
location |
string | Formatted location (e.g., "Sandusky, Ohio") |
operator |
string | Park operating company |
openingYear |
integer | Year park opened |
status |
string | Park status: open, closed, seasonal |
description |
string | Park description |
website |
string | Official website URL |
imageUrl |
string | Primary park image URL |
averageRating |
float | Average user rating (detail view only) |
rideCount |
integer | Total number of rides (detail view only) |
coasterCount |
integer | Number of roller coasters (detail view only) |
sizeAcres |
float | Park size in acres (detail view only) |
operatingSeason |
string | Operating season description (detail view only) |
Ride Data Structure
| Field | Type | Description |
|---|---|---|
id |
integer | Unique ride identifier |
name |
string | Ride name |
slug |
string | URL-friendly ride identifier |
parkId |
integer | Parent park ID |
parkName |
string | Parent park name |
parkSlug |
string | Parent park slug |
category |
string | Ride category |
manufacturer |
string | Ride manufacturer |
designer |
string | Ride designer |
openingYear |
integer | Year ride opened |
height |
float | Height in feet (coasters only) |
speed |
float | Speed in mph (coasters only) |
length |
float | Length in feet (coasters only) |
inversions |
integer | Number of inversions (coasters only) |
status |
string | Ride status |
description |
string | Ride description |
imageUrl |
string | Primary ride image URL |
thrillLevel |
string | Calculated thrill level |
minHeightIn |
integer | Minimum height requirement (detail view only) |
maxHeightIn |
integer | Maximum height requirement (detail view only) |
capacityPerHour |
integer | Hourly capacity (detail view only) |
rideDurationSeconds |
integer | Ride duration in seconds (detail view only) |
averageRating |
float | Average user rating (detail view only) |
closingDate |
date | Date ride closed (detail view only) |
statusSince |
date | Date status changed (detail view only) |
coasterStats |
object | Detailed coaster statistics (detail view only) |
Coaster Statistics Structure
| Field | Type | Description |
|---|---|---|
trackMaterial |
string | Track material (steel, wood) |
coasterType |
string | Coaster type (hypercoaster, inverted, etc.) |
launchType |
string | Launch mechanism |
maxDropHeightFt |
float | Maximum drop height in feet |
rideTimeSeconds |
integer | Total ride time in seconds |
trainsCount |
integer | Number of trains |
carsPerTrain |
integer | Cars per train |
seatsPerCar |
integer | Seats per car |
trainStyle |
string | Train style (open_air, enclosed) |
trackType |
string | Track configuration |
Field Mappings
Django to Frontend Field Conversion
The API automatically converts Django's snake_case field names to JavaScript's camelCase convention:
| Django Model | Frontend API |
|---|---|
opening_date |
openingYear |
min_height_in |
minHeightIn |
max_height_in |
maxHeightIn |
capacity_per_hour |
capacityPerHour |
ride_duration_seconds |
rideDurationSeconds |
coaster_stats |
coasterStats |
size_acres |
sizeAcres |
ride_count |
rideCount |
coaster_count |
coasterCount |
average_rating |
averageRating |
Status Mappings
Park Status
| Django | Frontend |
|---|---|
OPERATING |
open |
CLOSED_TEMP |
seasonal |
CLOSED_PERM |
closed |
UNDER_CONSTRUCTION |
closed |
DEMOLISHED |
closed |
RELOCATED |
closed |
Ride Status
| Django | Frontend |
|---|---|
OPERATING |
operating |
CLOSED_TEMP |
closed |
SBNO |
sbno |
CLOSING |
closed |
CLOSED_PERM |
closed |
UNDER_CONSTRUCTION |
under_construction |
DEMOLISHED |
closed |
RELOCATED |
closed |
Category Mappings
Ride Categories
| Django | Frontend |
|---|---|
RC |
roller_coaster |
DR |
dark_ride |
FR |
flat_ride |
WR |
water_ride |
TR |
transport |
OT |
other |
Error Handling
The API returns standard HTTP status codes with detailed error information:
Error Response Format
{
"error": {
"code": "NOT_FOUND",
"message": "Park with id 999 not found",
"details": {}
}
}
Common HTTP Status Codes
200 OK- Successful request201 Created- Resource created successfully400 Bad Request- Invalid request data401 Unauthorized- Authentication required403 Forbidden- Insufficient permissions404 Not Found- Resource not found429 Too Many Requests- Rate limit exceeded500 Internal Server Error- Server error
Pagination
List endpoints support pagination with the following format:
{
"count": 150,
"next": "http://localhost:8000/api/parks/?page=2",
"previous": null,
"results": [...]
}
Query Parameters:
page- Page number (default: 1)page_size- Items per page (default: 20, max: 100)
Rate Limiting
The API implements rate limiting to prevent abuse:
- Anonymous users: 100 requests per hour
- Authenticated users: 1000 requests per hour
Rate limit headers are included in responses:
X-RateLimit-Limit- Request limit per hourX-RateLimit-Remaining- Remaining requestsX-RateLimit-Reset- Time until reset (Unix timestamp)
CORS Configuration
The API is configured to work with the Vue.js frontend:
- Allowed origins:
http://localhost:5174(development) - Allowed methods:
GET,POST,PUT,DELETE,OPTIONS - Allowed headers:
Content-Type,Authorization,X-Requested-With
Frontend Integration
Vue.js Service Layer
The frontend uses dedicated service functions for API communication:
// services/parkService.ts
export const parkService = {
async getParks(params?: ParkQueryParams): Promise<PaginatedResponse<Park>> {
const response = await apiClient.get('/parks/', { params });
return response.data;
},
async getPark(id: number): Promise<ParkDetail> {
const response = await apiClient.get(`/parks/${id}/`);
return response.data;
}
};
Pinia Store Integration
API responses are managed through Pinia stores:
// stores/parks.ts
export const useParksStore = defineStore('parks', () => {
const parks = ref<Park[]>([]);
const loading = ref(false);
const fetchParks = async () => {
loading.value = true;
try {
const response = await parkService.getParks();
parks.value = response.results;
} finally {
loading.value = false;
}
};
return { parks, loading, fetchParks };
});
Development & Testing
API Testing with curl
# Get list of parks
curl "http://localhost:8000/api/parks/"
# Get specific park
curl "http://localhost:8000/api/parks/1/"
# Search parks
curl "http://localhost:8000/api/parks/?search=cedar"
# Filter by status
curl "http://localhost:8000/api/parks/?status=open"
Django REST Framework Browsable API
When DEBUG=True, the API provides a browsable interface at each endpoint URL. This interface allows:
- Interactive API browsing
- Form-based testing
- Authentication testing
- Request/response inspection
Future Enhancements
Planned Features
- Authentication & Authorization - JWT-based user authentication
- User Preferences - Personalized park/ride recommendations
- Image Upload - User-contributed photos
- Review System - User ratings and reviews
- Social Features - Following parks/rides, activity feeds
- Advanced Search - Full-text search with filters
- Real-time Updates - WebSocket support for live data
API Versioning
Future API versions will be supported via URL versioning:
/api/v1/parks/- Version 1 (current)/api/v2/parks/- Version 2 (future)
Support
For API-related questions or issues:
- Check the Django REST Framework documentation
- Review the frontend integration guide
- Create an issue in the project repository
Changelog
Version 1.0.0
- Initial API release
- Parks and rides endpoints
- Frontend-compatible serialization
- Pagination and filtering support
- CORS configuration for Vue.js integration