163 lines
4.6 KiB
Python
163 lines
4.6 KiB
Python
"""
|
|
Public API endpoints for matches.
|
|
|
|
This module provides public endpoints for retrieving matches without authentication.
|
|
"""
|
|
|
|
from datetime import datetime
|
|
from typing import Optional
|
|
from fastapi import APIRouter, Query, HTTPException, status, Depends
|
|
from sqlalchemy.orm import Session
|
|
|
|
from app.database import get_db
|
|
from app.models.match import Match
|
|
from app.schemas.public import (
|
|
PublicMatchResponse,
|
|
SuccessResponse,
|
|
SuccessMeta
|
|
)
|
|
|
|
router = APIRouter(prefix="/api/public/v1", tags=["public-matches"])
|
|
|
|
|
|
@router.get("/matches", response_model=SuccessResponse)
|
|
def get_public_matches(
|
|
limit: int = Query(20, ge=1, le=100, description="Maximum number of matches to return (max 100)"),
|
|
offset: int = Query(0, ge=0, description="Number of matches to skip"),
|
|
league: Optional[str] = Query(None, description="Filter by league name (case-insensitive)"),
|
|
status_filter: Optional[str] = Query(None, alias="status", description="Filter by match status"),
|
|
db: Session = Depends(get_db)
|
|
):
|
|
"""
|
|
Get public matches with pagination and filters.
|
|
|
|
This endpoint provides publicly accessible matches without authentication.
|
|
Data is limited to non-sensitive information only.
|
|
|
|
Args:
|
|
limit: Maximum number of matches to return (1-100, default: 20)
|
|
offset: Number of matches to skip (default: 0)
|
|
league: Optional filter by league name (case-insensitive)
|
|
status: Optional filter by match status (e.g., "scheduled", "completed", "ongoing")
|
|
db: Database session (injected)
|
|
|
|
Returns:
|
|
Paginated list of public matches
|
|
|
|
Example Requests:
|
|
GET /api/public/v1/matches
|
|
GET /api/public/v1/matches?limit=10&offset=0
|
|
GET /api/public/v1/matches?league=Ligue%201
|
|
GET /api/public/v1/matches?status=scheduled
|
|
|
|
Example Response:
|
|
{
|
|
"data": [
|
|
{
|
|
"id": 1,
|
|
"home_team": "PSG",
|
|
"away_team": "Olympique de Marseille",
|
|
"date": "2026-01-18T20:00:00Z",
|
|
"league": "Ligue 1",
|
|
"status": "scheduled"
|
|
}
|
|
],
|
|
"meta": {
|
|
"total": 45,
|
|
"limit": 20,
|
|
"offset": 0,
|
|
"timestamp": "2026-01-17T14:30:00Z",
|
|
"version": "v1"
|
|
}
|
|
}
|
|
"""
|
|
# Build query
|
|
query = db.query(Match)
|
|
|
|
# Apply filters
|
|
if league:
|
|
query = query.filter(Match.league.ilike(f"%{league}%"))
|
|
|
|
if status_filter:
|
|
query = query.filter(Match.status == status_filter)
|
|
|
|
# Get total count
|
|
total = query.count()
|
|
|
|
# Apply pagination
|
|
matches = query.order_by(Match.date).offset(offset).limit(limit).all()
|
|
|
|
# Build response
|
|
match_responses = []
|
|
for match in matches:
|
|
match_responses.append({
|
|
"id": match.id,
|
|
"home_team": match.home_team,
|
|
"away_team": match.away_team,
|
|
"date": match.date.isoformat() if match.date else None,
|
|
"league": match.league,
|
|
"status": match.status
|
|
})
|
|
|
|
return {
|
|
"data": match_responses,
|
|
"meta": {
|
|
"total": total,
|
|
"limit": limit,
|
|
"offset": offset,
|
|
"timestamp": datetime.utcnow().isoformat() + "Z",
|
|
"version": "v1"
|
|
}
|
|
}
|
|
|
|
|
|
@router.get("/matches/{match_id}", response_model=PublicMatchResponse)
|
|
def get_public_match(
|
|
match_id: int,
|
|
db: Session = Depends(get_db)
|
|
):
|
|
"""
|
|
Get a specific public match by ID.
|
|
|
|
This endpoint provides a publicly accessible match without authentication.
|
|
|
|
Args:
|
|
match_id: ID of match
|
|
db: Database session (injected)
|
|
|
|
Returns:
|
|
Public match details
|
|
|
|
Raises:
|
|
404: If match doesn't exist
|
|
|
|
Example Request:
|
|
GET /api/public/v1/matches/1
|
|
|
|
Example Response:
|
|
{
|
|
"id": 1,
|
|
"home_team": "PSG",
|
|
"away_team": "Olympique de Marseille",
|
|
"date": "2026-01-18T20:00:00Z",
|
|
"league": "Ligue 1",
|
|
"status": "scheduled"
|
|
}
|
|
"""
|
|
match = db.query(Match).filter(Match.id == match_id).first()
|
|
|
|
if not match:
|
|
raise HTTPException(
|
|
status_code=status.HTTP_404_NOT_FOUND,
|
|
detail=f"Match with id {match_id} not found"
|
|
)
|
|
|
|
return {
|
|
"id": match.id,
|
|
"home_team": match.home_team,
|
|
"away_team": match.away_team,
|
|
"date": match.date.isoformat() if match.date else None,
|
|
"league": match.league,
|
|
"status": match.status
|
|
}
|