13 KiB
ThrillWiki Frontend API Documentation
This document provides comprehensive documentation for frontend developers on how to integrate with the ThrillWiki API endpoints.
Base URL
http://localhost:8000/api/v1/
Authentication
Most endpoints are publicly accessible. Admin endpoints require authentication.
Content Discovery Endpoints
Trending Content
Get trending parks and rides based on view counts, ratings, and recency.
Endpoint: GET /trending/content/
Parameters:
limit(optional): Number of trending items to return (default: 20, max: 100)timeframe(optional): Timeframe for trending calculation - "day", "week", "month" (default: "week")
Response Format:
{
"trending_rides": [
{
"id": 137,
"name": "Steel Vengeance",
"park": "Cedar Point",
"category": "ride",
"rating": 4.8,
"rank": 1,
"views": 15234,
"views_change": "+25%",
"slug": "steel-vengeance",
"date_opened": "2018-05-05",
"url": "https://thrillwiki.com/parks/cedar-point/rides/steel-vengeance/",
"park_url": "https://thrillwiki.com/parks/cedar-point/",
"card_image": "https://media.thrillwiki.com/rides/steel-vengeance-card.jpg"
}
],
"trending_parks": [
{
"id": 1,
"name": "Cedar Point",
"park": "Cedar Point",
"category": "park",
"rating": 4.6,
"rank": 1,
"views": 45678,
"views_change": "+12%",
"slug": "cedar-point",
"date_opened": "1870-01-01",
"url": "https://thrillwiki.com/parks/cedar-point/",
"card_image": "https://media.thrillwiki.com/parks/cedar-point-card.jpg",
"city": "Sandusky",
"state": "Ohio",
"country": "USA",
"primary_company": "Cedar Fair"
}
],
"latest_reviews": []
}
New Content
Get recently added parks and rides.
Endpoint: GET /trending/new/
Parameters:
limit(optional): Number of new items to return (default: 20, max: 100)days(optional): Number of days to look back for new content (default: 30, max: 365)
Response Format:
{
"recently_added": [
{
"id": 137,
"name": "Steel Vengeance",
"park": "Cedar Point",
"category": "ride",
"date_added": "2018-05-05",
"date_opened": "2018-05-05",
"slug": "steel-vengeance",
"url": "https://thrillwiki.com/parks/cedar-point/rides/steel-vengeance/",
"park_url": "https://thrillwiki.com/parks/cedar-point/",
"card_image": "https://media.thrillwiki.com/rides/steel-vengeance-card.jpg"
},
{
"id": 42,
"name": "Dollywood",
"park": "Dollywood",
"category": "park",
"date_added": "2018-05-01",
"date_opened": "1986-05-03",
"slug": "dollywood",
"url": "https://thrillwiki.com/parks/dollywood/",
"card_image": "https://media.thrillwiki.com/parks/dollywood-card.jpg",
"city": "Pigeon Forge",
"state": "Tennessee",
"country": "USA",
"primary_company": "Dollywood Company"
}
],
"newly_opened": [
{
"id": 136,
"name": "Time Traveler",
"park": "Silver Dollar City",
"category": "ride",
"date_added": "2018-04-28",
"date_opened": "2018-04-28",
"slug": "time-traveler",
"url": "https://thrillwiki.com/parks/silver-dollar-city/rides/time-traveler/",
"park_url": "https://thrillwiki.com/parks/silver-dollar-city/",
"card_image": "https://media.thrillwiki.com/rides/time-traveler-card.jpg"
}
],
"upcoming": []
}
Key Changes:
- REMOVED:
locationfield from all trending and new content responses - ADDED:
parkfield - shows the park name for both parks and rides - ADDED:
date_openedfield - shows when the park/ride originally opened
Trigger Content Calculation (Admin Only)
Manually trigger the calculation of trending and new content.
Endpoint: POST /trending/calculate/
Authentication: Admin access required
Response Format:
{
"message": "Trending content calculation completed",
"trending_completed": true,
"new_content_completed": true,
"completion_time": "2025-08-28 16:41:42",
"trending_output": "Successfully calculated 50 trending items for all",
"new_content_output": "Successfully calculated 50 new items for all"
}
Data Field Descriptions
Common Fields
id: Unique identifier for the itemname: Display name of the park or ridepark: Name of the park (for rides, this is the parent park; for parks, this is the park itself)category: Type of content ("park" or "ride")slug: URL-friendly identifierdate_opened: ISO date string of when the park/ride originally opened (YYYY-MM-DD format)url: Frontend URL for direct navigation to the item's detail pagecard_image: URL to the card image for display in lists and grids (available for both parks and rides)
Park-Specific Fields
city: City where the park is located (shortened format)state: State/province where the park is located (shortened format)country: Country where the park is located (shortened format)primary_company: Name of the primary operating company for the park
Ride-Specific Fields
park_url: Frontend URL for the ride's parent park
Trending-Specific Fields
rating: Average user rating (0.0 to 10.0)rank: Position in trending list (1-based)views: Current view countviews_change: Percentage change in views (e.g., "+25%")
New Content-Specific Fields
date_added: ISO date string of when the item was added to the database (YYYY-MM-DD format)
Implementation Notes
Content Categorization
The API automatically categorizes new content based on dates:
- Recently Added: Items added to the database in the last 30 days
- Newly Opened: Items that opened in the last year
- Upcoming: Future openings (currently empty, reserved for future use)
Caching
- Trending content is cached for 24 hours
- New content is cached for 30 minutes
- Use the admin trigger endpoint to force cache refresh
Error Handling
All endpoints return standard HTTP status codes:
200: Success400: Bad request (invalid parameters)403: Forbidden (admin endpoints only)500: Internal server error
Rate Limiting
No rate limiting is currently implemented, but it may be added in the future.
Migration from Previous API Format
If you were previously using the API with location fields, update your frontend code:
Before:
const ride = {
name: "Steel Vengeance",
location: "Cedar Point", // OLD FIELD
category: "ride"
};
After:
const ride = {
name: "Steel Vengeance",
park: "Cedar Point", // NEW FIELD
category: "ride",
date_opened: "2018-05-05" // NEW FIELD
};
Backend Architecture Changes
The trending system has been migrated from Celery-based async processing to Django management commands for better reliability and simpler deployment:
Management Commands
python manage.py calculate_trending- Calculate trending contentpython manage.py calculate_new_content- Calculate new content
Direct Calculation
The API now uses direct calculation instead of async tasks, providing immediate results while maintaining performance through caching.
URL Fields for Frontend Navigation
All API responses now include dynamically generated url fields that provide direct links to the frontend pages for each entity. These URLs are generated based on the configured FRONTEND_DOMAIN setting.
URL Patterns
- Parks:
https://domain.com/parks/{park-slug}/ - Rides:
https://domain.com/parks/{park-slug}/rides/{ride-slug}/ - Ride Models:
https://domain.com/rides/manufacturers/{manufacturer-slug}/{model-slug}/ - Companies (Operators):
https://domain.com/parks/operators/{operator-slug}/ - Companies (Property Owners):
https://domain.com/parks/owners/{owner-slug}/ - Companies (Manufacturers):
https://domain.com/rides/manufacturers/{manufacturer-slug}/ - Companies (Designers):
https://domain.com/rides/designers/{designer-slug}/
Domain Separation Rules
CRITICAL: Company URLs follow strict domain separation:
- Parks Domain: OPERATOR and PROPERTY_OWNER roles generate URLs under
/parks/ - Rides Domain: MANUFACTURER and DESIGNER roles generate URLs under
/rides/ - Companies with multiple roles use their primary role (first in the roles array) for URL generation
- URLs are auto-generated when entities are saved and stored in the database
Example Response with URL Fields
{
"id": 1,
"name": "Steel Vengeance",
"slug": "steel-vengeance",
"park": {
"id": 1,
"name": "Cedar Point",
"slug": "cedar-point",
"url": "https://thrillwiki.com/parks/cedar-point/"
},
"url": "https://thrillwiki.com/parks/cedar-point/rides/steel-vengeance/",
"manufacturer": {
"id": 1,
"name": "Rocky Mountain Construction",
"slug": "rocky-mountain-construction",
"url": "https://thrillwiki.com/rides/manufacturers/rocky-mountain-construction/"
}
}
Example Usage
Fetch Trending Content
const response = await fetch('/api/v1/trending/content/?limit=10');
const data = await response.json();
// Display trending rides with clickable links
data.trending_rides.forEach(ride => {
console.log(`${ride.name} at ${ride.park} - opened ${ride.date_opened}`);
console.log(`Visit: ${ride.url}`);
});
Fetch New Content
const response = await fetch('/api/v1/trending/new/?limit=5&days=7');
const data = await response.json();
// Display newly opened attractions
data.newly_opened.forEach(item => {
console.log(`${item.name} at ${item.park} - opened ${item.date_opened}`);
});
Admin: Trigger Calculation
const response = await fetch('/api/v1/trending/calculate/', {
method: 'POST',
headers: {
'Authorization': 'Bearer YOUR_ADMIN_TOKEN',
'Content-Type': 'application/json'
}
});
const result = await response.json();
console.log(result.message);
## Reviews Endpoints
### Latest Reviews
Get the latest reviews from both parks and rides across the platform.
**Endpoint:** `GET /reviews/latest/`
**Parameters:**
- `limit` (optional): Number of reviews to return (default: 20, max: 100)
**Response Format:**
```json
{
"count": 15,
"results": [
{
"id": 42,
"type": "ride",
"title": "Amazing coaster experience!",
"content_snippet": "This ride was absolutely incredible. The airtime was perfect and the inversions were smooth...",
"rating": 9,
"created_at": "2025-08-28T21:30:00Z",
"user": {
"username": "coaster_fan_2024",
"display_name": "Coaster Fan",
"avatar_url": "https://media.thrillwiki.com/avatars/user123.jpg"
},
"subject_name": "Steel Vengeance",
"subject_slug": "steel-vengeance",
"subject_url": "/parks/cedar-point/rides/steel-vengeance/",
"park_name": "Cedar Point",
"park_slug": "cedar-point",
"park_url": "/parks/cedar-point/"
},
{
"id": 38,
"type": "park",
"title": "Great family park",
"content_snippet": "Had a wonderful time with the family. The park was clean, staff was friendly, and there were rides for all ages...",
"rating": 8,
"created_at": "2025-08-28T20:15:00Z",
"user": {
"username": "family_fun",
"display_name": "Family Fun",
"avatar_url": "/static/images/default-avatar.png"
},
"subject_name": "Dollywood",
"subject_slug": "dollywood",
"subject_url": "/parks/dollywood/",
"park_name": null,
"park_slug": null,
"park_url": null
}
]
}
Field Descriptions:
id: Unique review identifiertype: Review type - "park" or "ride"title: Review title/headlinecontent_snippet: Truncated review content (max 150 characters with smart word breaking)rating: User rating from 1-10created_at: ISO timestamp when review was createduser: User information objectusername: User's unique usernamedisplay_name: User's display name (falls back to username if not set)avatar_url: URL to user's avatar image (uses default if not set)
subject_name: Name of the reviewed item (park or ride)subject_slug: URL slug of the reviewed itemsubject_url: Frontend URL to the reviewed item's detail pagepark_name: For ride reviews, the name of the parent park (null for park reviews)park_slug: For ride reviews, the slug of the parent park (null for park reviews)park_url: For ride reviews, the URL to the parent park (null for park reviews)
Authentication: None required (public endpoint)
Example Usage:
// Fetch latest 10 reviews
const response = await fetch('/api/v1/reviews/latest/?limit=10');
const data = await response.json();
// Display reviews
data.results.forEach(review => {
console.log(`${review.user.display_name} rated ${review.subject_name}: ${review.rating}/10`);
console.log(`"${review.title}" - ${review.content_snippet}`);
if (review.type === 'ride') {
console.log(`Ride at ${review.park_name}`);
}
});
Error Responses:
400 Bad Request: Invalid limit parameter500 Internal Server Error: Database or server error
Notes:
- Reviews are filtered to only show published reviews (
is_published=True) - Results are sorted by creation date (newest first)
- Content snippets are intelligently truncated at word boundaries
- Avatar URLs fall back to default avatar if user hasn't uploaded one
- The endpoint combines reviews from both parks and rides into a single chronological feed