- 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
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