Files
thrillwiki_django_no_react/docs/park-detail-endpoint-documentation.md
pacnpal 0fd6dc2560 feat: Enhance Park Detail Endpoint with Media URL Service Integration
- Updated ParkDetailOutputSerializer to utilize MediaURLService for generating Cloudflare URLs and friendly URLs for park photos.
- Added support for multiple lookup methods (ID and slug) in the park detail endpoint.
- Improved documentation for the park detail endpoint, including request properties and response structure.
- Created MediaURLService for generating SEO-friendly URLs and handling Cloudflare image URLs.
- Comprehensive updates to frontend documentation to reflect new endpoint capabilities and usage examples.
- Added detailed park detail endpoint documentation, including request and response structures, field descriptions, and usage examples.
2025-08-31 16:45:47 -04:00

17 KiB
Raw Blame History

Park Detail Endpoint - Complete Documentation

Endpoint Overview

URL: GET /api/v1/parks/{identifier}/

Description: Retrieve comprehensive park details including location, photos, areas, rides, and company information.

Authentication: None required (public endpoint)

Supports Multiple Lookup Methods:

  • By ID: /api/v1/parks/123/
  • By current slug: /api/v1/parks/cedar-point/
  • By historical slug: /api/v1/parks/old-cedar-point-name/

Request Properties

Path Parameters

Parameter Type Required Description
identifier string Yes Park ID (integer) or slug (string). Supports current and historical slugs.

Query Parameters

None required - This endpoint returns full park details by default without any query parameters.

Request Headers

Header Required Description
Accept No application/json (default)
Content-Type No Not applicable for GET requests

Response Structure

Success Response (200 OK)

{
  "id": 1,
  "name": "Cedar Point",
  "slug": "cedar-point",
  "status": "OPERATING",
  "description": "America's Roller Coast",
  "park_type": "THEME_PARK",
  
  // Dates and Operations
  "opening_date": "1870-01-01",
  "closing_date": null,
  "operating_season": "May - October",
  "size_acres": 364.0,
  "website": "https://cedarpoint.com",
  
  // Statistics
  "average_rating": 4.5,
  "coaster_count": 17,
  "ride_count": 70,
  
  // Location Information
  "location": {
    "id": 1,
    "latitude": 41.4793,
    "longitude": -82.6833,
    "street_address": "1 Cedar Point Dr",
    "city": "Sandusky",
    "state": "Ohio",
    "country": "United States",
    "continent": "North America",
    "postal_code": "44870",
    "formatted_address": "1 Cedar Point Dr, Sandusky, OH 44870, United States"
  },
  
  // Company Information
  "operator": {
    "id": 1,
    "name": "Cedar Fair",
    "slug": "cedar-fair",
    "roles": ["OPERATOR"],
    "description": "Leading amusement park operator",
    "website": "https://cedarfair.com",
    "founded_year": 1983
  },
  "property_owner": {
    "id": 1,
    "name": "Cedar Fair",
    "slug": "cedar-fair",
    "roles": ["OPERATOR", "PROPERTY_OWNER"],
    "description": "Leading amusement park operator",
    "website": "https://cedarfair.com",
    "founded_year": 1983
  },
  
  // Park Areas/Themed Sections
  "areas": [
    {
      "id": 1,
      "name": "Frontier Town",
      "slug": "frontier-town",
      "description": "Wild West themed area"
    },
    {
      "id": 2,
      "name": "Millennium Island",
      "slug": "millennium-island",
      "description": "Home to Millennium Force"
    }
  ],
  
  // Photo Information
                "photos": [
                    {
                        "id": 456,
                        "image_url": "https://imagedelivery.net/account-hash/def789ghi012/public",
                        "image_variants": {
                            "thumbnail": "https://imagedelivery.net/account-hash/def789ghi012/thumbnail",
                            "medium": "https://imagedelivery.net/account-hash/def789ghi012/medium",
                            "large": "https://imagedelivery.net/account-hash/def789ghi012/large",
                            "public": "https://imagedelivery.net/account-hash/def789ghi012/public"
                        },
                        "friendly_urls": {
                            "thumbnail": "/parks/cedar-point/photos/beautiful-park-entrance-456-thumbnail.jpg",
                            "medium": "/parks/cedar-point/photos/beautiful-park-entrance-456-medium.jpg",
                            "large": "/parks/cedar-point/photos/beautiful-park-entrance-456-large.jpg",
                            "public": "/parks/cedar-point/photos/beautiful-park-entrance-456.jpg"
                        },
                        "caption": "Beautiful park entrance",
                        "alt_text": "Cedar Point main entrance with flags",
                        "is_primary": true
                    }
                ],
  
  // Primary Photo (designated main photo)
  "primary_photo": {
    "id": 456,
    "image_url": "https://imagedelivery.net/account-hash/def789ghi012/public",
    "image_variants": {
      "thumbnail": "https://imagedelivery.net/account-hash/def789ghi012/thumbnail",
      "medium": "https://imagedelivery.net/account-hash/def789ghi012/medium",
      "large": "https://imagedelivery.net/account-hash/def789ghi012/large",
      "public": "https://imagedelivery.net/account-hash/def789ghi012/public"
    },
    "caption": "Beautiful park entrance",
    "alt_text": "Cedar Point main entrance with flags"
  },
  
  // Banner Image (for hero sections)
  "banner_image": {
    "id": 456,
    "image_url": "https://imagedelivery.net/account-hash/def789ghi012/public",
    "image_variants": {
      "thumbnail": "https://imagedelivery.net/account-hash/def789ghi012/thumbnail",
      "medium": "https://imagedelivery.net/account-hash/def789ghi012/medium",
      "large": "https://imagedelivery.net/account-hash/def789ghi012/large",
      "public": "https://imagedelivery.net/account-hash/def789ghi012/public"
    },
    "caption": "Beautiful park entrance",
    "alt_text": "Cedar Point main entrance with flags",
    "is_fallback": false
  },
  
  // Card Image (for listings/cards)
  "card_image": {
    "id": 456,
    "image_url": "https://imagedelivery.net/account-hash/def789ghi012/public",
    "image_variants": {
      "thumbnail": "https://imagedelivery.net/account-hash/def789ghi012/thumbnail",
      "medium": "https://imagedelivery.net/account-hash/def789ghi012/medium",
      "large": "https://imagedelivery.net/account-hash/def789ghi012/large",
      "public": "https://imagedelivery.net/account-hash/def789ghi012/public"
    },
    "caption": "Beautiful park entrance",
    "alt_text": "Cedar Point main entrance with flags",
    "is_fallback": false
  },
  
  // Frontend URL
  "url": "https://thrillwiki.com/parks/cedar-point/",
  
  // Metadata
  "created_at": "2024-01-01T00:00:00Z",
  "updated_at": "2024-01-15T12:30:00Z"
}

Error Responses

404 Not Found

{
  "detail": "Park not found"
}

500 Internal Server Error

{
  "detail": "Internal server error"
}

Field Descriptions

Core Park Information

Field Type Description
id integer Unique park identifier
name string Official park name
slug string URL-friendly identifier
status string Operational status (see Status Values)
description string Park description/tagline
park_type string Park category (see Park Type Values)

Operational Details

Field Type Description
opening_date date Park opening date (YYYY-MM-DD)
closing_date date Park closing date (null if still operating)
operating_season string Seasonal operation description
size_acres decimal Park size in acres
website string Official park website URL

Statistics

Field Type Description
average_rating decimal Average user rating (1-10 scale)
coaster_count integer Number of roller coasters
ride_count integer Total number of rides

Location Object

Field Type Description
id integer Location record ID
latitude float Geographic latitude
longitude float Geographic longitude
street_address string Street address
city string City name
state string State/province
country string Country name
continent string Continent name
postal_code string ZIP/postal code
formatted_address string Complete formatted address

Company Objects (Operator/Property Owner)

Field Type Description
id integer Company ID
name string Company name
slug string URL-friendly identifier
roles array Company roles (OPERATOR, PROPERTY_OWNER, etc.)
description string Company description
website string Company website
founded_year integer Year company was founded

Area Objects

Field Type Description
id integer Area ID
name string Area/section name
slug string URL-friendly identifier
description string Area description

Photo Objects

Field Type Description
id integer Photo ID
image_url string Base Cloudflare image URL
image_variants object Available image sizes/transformations
caption string Photo caption
alt_text string Accessibility alt text
is_primary boolean Whether this is the primary photo
is_fallback boolean Whether this is a fallback image

Image Variants Object

Field Type Description
thumbnail string Small thumbnail URL (150x150)
medium string Medium size URL (500x500)
large string Large size URL (1200x1200)
public string Full size public URL

Enumerated Values

Status Values

Value Description
OPERATING Currently operating
CLOSED_TEMP Temporarily closed
CLOSED_PERM Permanently closed
UNDER_CONSTRUCTION Under construction
DEMOLISHED Demolished
RELOCATED Relocated

Park Type Values

Value Description
THEME_PARK Theme park
AMUSEMENT_PARK Amusement park
WATER_PARK Water park
FAMILY_ENTERTAINMENT_CENTER Family entertainment center
CARNIVAL Carnival
FAIR Fair
PIER Pier
BOARDWALK Boardwalk
SAFARI_PARK Safari park
ZOO Zoo
OTHER Other

Usage Examples

JavaScript/TypeScript

// Fetch by ID
const parkById = await fetch('/api/v1/parks/123/');
const parkData = await parkById.json();

// Fetch by current slug
const parkBySlug = await fetch('/api/v1/parks/cedar-point/');
const parkData2 = await parkBySlug.json();

// Fetch by historical slug
const parkByHistoricalSlug = await fetch('/api/v1/parks/old-name/');
const parkData3 = await parkByHistoricalSlug.json();

// Access different image sizes
const thumbnailUrl = parkData.primary_photo?.image_variants.thumbnail;
const fullSizeUrl = parkData.primary_photo?.image_variants.public;

Python

import requests

# Fetch park details
response = requests.get('https://api.thrillwiki.com/api/v1/parks/cedar-point/')
park_data = response.json()

# Access park information
park_name = park_data['name']
location = park_data['location']
operator = park_data['operator']
photos = park_data['photos']

cURL

# Fetch by slug
curl -X GET "https://api.thrillwiki.com/api/v1/parks/cedar-point/" \
     -H "Accept: application/json"

# Fetch by ID
curl -X GET "https://api.thrillwiki.com/api/v1/parks/123/" \
     -H "Accept: application/json"
  • Park List: GET /api/v1/parks/ - List parks with filtering
  • Park Photos: GET /api/v1/parks/{id}/photos/ - Manage park photos
  • Park Areas: GET /api/v1/parks/{id}/areas/ - Park themed areas
  • Park Image Settings: PATCH /api/v1/parks/{id}/image-settings/ - Set banner/card images

Photo Handling Details

Photo Upload vs Display Distinction

Important: You can upload unlimited photos per park, but the park detail endpoint shows only the 10 most relevant photos for performance optimization.

Photo Upload Capacity

  • No Upload Limit: Upload unlimited photos per park via POST /api/v1/parks/{park_id}/photos/
  • Storage: All photos stored in database and Cloudflare Images
  • Approval System: Each photo goes through moderation (is_approved field)
  • Photo Types: Categorize photos (banner, card, gallery, etc.)
  • Bulk Upload: Support for multiple photo uploads

Display Limit (Detail Endpoint)

  • 10 Photo Limit: Only applies to this park detail endpoint response
  • Smart Selection: Shows 10 most relevant photos using intelligent ordering:
    1. Primary photos first (-is_primary)
    2. Newest photos next (-created_at)
    3. Only approved photos (is_approved=True)

Complete Photo Access

All Photos Available Via Dedicated Endpoint

GET /api/v1/parks/{park_id}/photos/
  • No Limit: Returns all uploaded photos for the park
  • Pagination: Supports pagination for large photo collections
  • Filtering: Filter by photo type, approval status, etc.
  • Full Management: Complete CRUD operations for all photos

Photo URL Structure Per Park

Maximum Possible URLs per park:

  • General photos: 10 photos × 4 variants = 40 URLs
  • Primary photo: 1 photo × 4 variants = 4 URLs
  • Banner image: 1 photo × 4 variants = 4 URLs
  • Card image: 1 photo × 4 variants = 4 URLs
  • Total Maximum: 52 photo URLs per park

Each photo includes 4 Cloudflare transformation URLs:

  1. thumbnail: Optimized for small previews (150x150)
  2. medium: Medium resolution for general use (500x500)
  3. large: High resolution for detailed viewing (1200x1200)
  4. public: Original/full size image

Practical Example

A park could have:

  • 50 uploaded photos (all stored in system)
  • 30 approved photos (available for public display)
  • 10 photos shown in park detail endpoint (most relevant)
  • All 30 approved photos accessible via /api/v1/parks/{id}/photos/

Frontend Implementation Strategy

// Get park with essential photos (fast initial load)
const park = await fetch('/api/v1/parks/cedar-point/');

// Get complete photo gallery when needed (e.g., photo gallery page)
const allPhotos = await fetch('/api/v1/parks/123/photos/?page_size=50');

Friendly URLs for Photos

NEW FEATURE: Each photo now includes both Cloudflare URLs and SEO-friendly URLs.

URL Structure

/parks/{park-slug}/photos/{caption-slug}-{photo-id}-{variant}.jpg

Examples:

  • /parks/cedar-point/photos/beautiful-park-entrance-456.jpg (public/original)
  • /parks/cedar-point/photos/beautiful-park-entrance-456-thumbnail.jpg
  • /parks/cedar-point/photos/beautiful-park-entrance-456-medium.jpg
  • /parks/cedar-point/photos/beautiful-park-entrance-456-large.jpg

Benefits

  • SEO Optimized: Descriptive URLs improve search engine ranking
  • User Friendly: URLs are readable and meaningful
  • Consistent: Follows predictable pattern across all photos
  • Backwards Compatible: Original Cloudflare URLs still available

Implementation

Each photo object now includes both URL types:

{
  "id": 456,
  "image_url": "https://imagedelivery.net/account-hash/def789ghi012/public",
  "image_variants": {
    "thumbnail": "https://imagedelivery.net/account-hash/def789ghi012/thumbnail",
    "medium": "https://imagedelivery.net/account-hash/def789ghi012/medium",
    "large": "https://imagedelivery.net/account-hash/def789ghi012/large",
    "public": "https://imagedelivery.net/account-hash/def789ghi012/public"
  },
  "friendly_urls": {
    "thumbnail": "/parks/cedar-point/photos/beautiful-park-entrance-456-thumbnail.jpg",
    "medium": "/parks/cedar-point/photos/beautiful-park-entrance-456-medium.jpg",
    "large": "/parks/cedar-point/photos/beautiful-park-entrance-456-large.jpg",
    "public": "/parks/cedar-point/photos/beautiful-park-entrance-456.jpg"
  },
  "caption": "Beautiful park entrance",
  "alt_text": "Cedar Point main entrance with flags"
}

Photo Management Features

  • Primary Photo: Designate which photo represents the park
  • Banner/Card Images: Set specific photos for different UI contexts
  • Fallback Logic: Banner and card images automatically fallback to latest approved photo if not explicitly set
  • Approval Workflow: Moderate photos before public display
  • Photo Metadata: Each photo includes caption, alt text, and categorization
  • Dual URL System: Both Cloudflare and friendly URLs provided for maximum flexibility

Performance Notes

  • Response includes optimized database queries with select_related and prefetch_related
  • Photos limited to 10 most recent approved photos for optimal response size
  • Image variants are pre-computed Cloudflare transformations for fast delivery
  • Historical slug lookup may require additional database queries
  • Smart photo selection ensures most relevant photos are included

Caching

  • No caching implemented at endpoint level
  • Cloudflare images are cached at CDN level
  • Consider implementing Redis caching for frequently accessed parks

Rate Limiting

  • No rate limiting currently implemented
  • Public endpoint accessible without authentication
  • Consider implementing rate limiting for production use