Files
thrillwiki_django_no_react/docs/frontend.md
pacnpal ac745cc541 ok
2025-08-28 23:20:09 -04:00

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

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: location field from all trending and new content responses
  • ADDED: park field - shows the park name for both parks and rides
  • ADDED: date_opened field - 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 item
  • name: Display name of the park or ride
  • park: 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 identifier
  • date_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 page
  • card_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
  • rating: Average user rating (0.0 to 10.0)
  • rank: Position in trending list (1-based)
  • views: Current view count
  • views_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: Success
  • 400: 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 content
  • python 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

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 identifier
  • type: Review type - "park" or "ride"
  • title: Review title/headline
  • content_snippet: Truncated review content (max 150 characters with smart word breaking)
  • rating: User rating from 1-10
  • created_at: ISO timestamp when review was created
  • user: User information object
    • username: User's unique username
    • display_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 item
  • subject_url: Frontend URL to the reviewed item's detail page
  • park_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 parameter
  • 500 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