Add REST API endpoints for team player statistics
Implemented complete REST API to retrieve NHL player statistics for entire teams:
Application Layer:
- Created DTOs for Player, SkaterStats, GoalieStats, and PlayerWithStatsDTO
- Implemented GetTeamPlayerStatsUseCase that orchestrates data retrieval
- Transforms domain entities to API-friendly DTOs
Presentation Layer:
- Created /api/v1/teams/{team_id}/players endpoint (all players)
- Created /api/v1/teams/{team_id}/players/skaters endpoint (skaters only)
- Created /api/v1/teams/{team_id}/players/goalies endpoint (goalies only)
- Integrated routes into main FastAPI application
Features:
- Retrieves complete roster for any NHL team by abbreviation
- Aggregates current season statistics for each player
- Differentiates between skater and goalie statistics
- Proper error handling with 404 for invalid teams
- Follows CLEAN architecture with dependency injection
Documentation:
- Created comprehensive API_GUIDE.md with usage examples
- Includes setup instructions, endpoint documentation
- Python, JavaScript, and cURL examples
- Complete list of NHL team abbreviations
Testing:
- Added test scripts for both direct adapter testing and REST API testing
- Verified functionality with Toronto Maple Leafs data
The REST API is now ready for integration with fantasy hockey analysis tools.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
265
API_GUIDE.md
Normal file
265
API_GUIDE.md
Normal file
@@ -0,0 +1,265 @@
|
||||
# REST API Guide - Project Kempe
|
||||
|
||||
This guide explains how to set up and use the REST API to retrieve NHL player statistics for entire teams.
|
||||
|
||||
## Setup Instructions
|
||||
|
||||
### 1. Install Dependencies
|
||||
|
||||
```bash
|
||||
cd /Users/michaelsimard/dev/services/project-kempe-backend
|
||||
|
||||
# Install all required packages
|
||||
pip3 install -r requirements.txt
|
||||
```
|
||||
|
||||
###2. Start the FastAPI Server
|
||||
|
||||
```bash
|
||||
# Option 1: Using uvicorn directly
|
||||
uvicorn src.presentation.api.main:app --reload --host 0.0.0.0 --port 8000
|
||||
|
||||
# Option 2: Using python module
|
||||
python3 -m uvicorn src.presentation.api.main:app --reload --host 0.0.0.0 --port 8000
|
||||
```
|
||||
|
||||
The server will start on `http://localhost:8000`
|
||||
|
||||
### 3. Verify Server is Running
|
||||
|
||||
Open your browser and visit:
|
||||
- **API Documentation**: http://localhost:8000/docs (Interactive Swagger UI)
|
||||
- **Alternative Docs**: http://localhost:8000/redoc
|
||||
- **Health Check**: http://localhost:8000/health
|
||||
|
||||
## Available Endpoints
|
||||
|
||||
### Get All Players with Stats for a Team
|
||||
|
||||
**Endpoint**: `GET /api/v1/teams/{team_id}/players`
|
||||
|
||||
**Example**:
|
||||
```bash
|
||||
curl http://localhost:8000/api/v1/teams/TOR/players
|
||||
```
|
||||
|
||||
**Response**: JSON array of all players (forwards, defensemen, goalies) with their current season statistics.
|
||||
|
||||
**Response Structure**:
|
||||
```json
|
||||
[
|
||||
{
|
||||
"player": {
|
||||
"id": "8478104",
|
||||
"first_name": "Sammy",
|
||||
"last_name": "Blais",
|
||||
"full_name": "Sammy Blais",
|
||||
"jersey_number": 79,
|
||||
"position": "F",
|
||||
"team_id": "TOR"
|
||||
},
|
||||
"stats": {
|
||||
"player_id": "8478104",
|
||||
"games_played": 8,
|
||||
"goals": 1,
|
||||
"assists": 2,
|
||||
"points": 3,
|
||||
"plus_minus": -2,
|
||||
"penalty_minutes": 4,
|
||||
"shots": 12,
|
||||
"shooting_percentage": 8.33,
|
||||
"time_on_ice_per_game": 14.5,
|
||||
"powerplay_goals": 0,
|
||||
"powerplay_points": 0,
|
||||
"shorthanded_goals": 0,
|
||||
"game_winning_goals": 0,
|
||||
"faceoff_percentage": null,
|
||||
"hits": 15,
|
||||
"blocked_shots": 3
|
||||
},
|
||||
"stats_type": "skater"
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
### Get Only Skaters for a Team
|
||||
|
||||
**Endpoint**: `GET /api/v1/teams/{team_id}/players/skaters`
|
||||
|
||||
**Example**:
|
||||
```bash
|
||||
curl http://localhost:8000/api/v1/teams/TOR/players/skaters
|
||||
```
|
||||
|
||||
**Response**: JSON array of only forwards and defensemen with their statistics.
|
||||
|
||||
### Get Only Goalies for a Team
|
||||
|
||||
**Endpoint**: `GET /api/v1/teams/{team_id}/players/goalies`
|
||||
|
||||
**Example**:
|
||||
```bash
|
||||
curl http://localhost:8000/api/v1/teams/TOR/players/goalies
|
||||
```
|
||||
|
||||
**Response**: JSON array of only goalies with their statistics.
|
||||
|
||||
**Goalie Stats Structure**:
|
||||
```json
|
||||
{
|
||||
"player": {
|
||||
"id": "8471679",
|
||||
"first_name": "Joseph",
|
||||
"last_name": "Woll",
|
||||
"full_name": "Joseph Woll",
|
||||
"jersey_number": 60,
|
||||
"position": "G",
|
||||
"team_id": "TOR"
|
||||
},
|
||||
"stats": {
|
||||
"player_id": "8471679",
|
||||
"games_played": 10,
|
||||
"games_started": 10,
|
||||
"wins": 6,
|
||||
"losses": 2,
|
||||
"overtime_losses": 2,
|
||||
"saves": 285,
|
||||
"shots_against": 308,
|
||||
"goals_against": 23,
|
||||
"save_percentage": 92.53,
|
||||
"goals_against_average": 2.30,
|
||||
"shutouts": 1,
|
||||
"time_on_ice": 600.5
|
||||
},
|
||||
"stats_type": "goalie"
|
||||
}
|
||||
```
|
||||
|
||||
## NHL Team Abbreviations
|
||||
|
||||
Use these three-letter abbreviations when making API calls:
|
||||
|
||||
**Atlantic Division**:
|
||||
- TOR - Toronto Maple Leafs
|
||||
- BOS - Boston Bruins
|
||||
- FLA - Florida Panthers
|
||||
- TBL - Tampa Bay Lightning
|
||||
- BUF - Buffalo Sabres
|
||||
- DET - Detroit Red Wings
|
||||
- OTT - Ottawa Senators
|
||||
- MTL - Montréal Canadiens
|
||||
|
||||
**Metropolitan Division**:
|
||||
- CAR - Carolina Hurricanes
|
||||
- NYR - New York Rangers
|
||||
- NJD - New Jersey Devils
|
||||
- PHI - Philadelphia Flyers
|
||||
- PIT - Pittsburgh Penguins
|
||||
- WSH - Washington Capitals
|
||||
- NYI - New York Islanders
|
||||
- CBJ - Columbus Blue Jackets
|
||||
|
||||
**Central Division**:
|
||||
- DAL - Dallas Stars
|
||||
- COL - Colorado Avalanche
|
||||
- WPG - Winnipeg Jets
|
||||
- MIN - Minnesota Wild
|
||||
- NSH - Nashville Predators
|
||||
- STL - St. Louis Blues
|
||||
- CHI - Chicago Blackhawks
|
||||
- UTA - Utah Mammoth
|
||||
|
||||
**Pacific Division**:
|
||||
- VGK - Vegas Golden Knights
|
||||
- EDM - Edmonton Oilers
|
||||
- LAK - Los Angeles Kings
|
||||
- VAN - Vancouver Canucks
|
||||
- SEA - Seattle Kraken
|
||||
- CGY - Calgary Flames
|
||||
- ANA - Anaheim Ducks
|
||||
- SJS - San Jose Sharks
|
||||
|
||||
## Using the API in Your Application
|
||||
|
||||
### Python Example
|
||||
|
||||
```python
|
||||
import httpx
|
||||
import asyncio
|
||||
|
||||
async def get_team_stats(team_id: str):
|
||||
async with httpx.AsyncClient() as client:
|
||||
response = await client.get(
|
||||
f"http://localhost:8000/api/v1/teams/{team_id}/players"
|
||||
)
|
||||
return response.json()
|
||||
|
||||
# Get Toronto Maple Leafs stats
|
||||
stats = asyncio.run(get_team_stats("TOR"))
|
||||
for player_data in stats:
|
||||
player = player_data["player"]
|
||||
print(f"{player['full_name']}: {player_data['stats_type']}")
|
||||
```
|
||||
|
||||
### JavaScript Example
|
||||
|
||||
```javascript
|
||||
async function getTeamStats(teamId) {
|
||||
const response = await fetch(
|
||||
`http://localhost:8000/api/v1/teams/${teamId}/players`
|
||||
);
|
||||
const data = await response.json();
|
||||
return data;
|
||||
}
|
||||
|
||||
// Get Toronto Maple Leafs stats
|
||||
getTeamStats('TOR').then(players => {
|
||||
players.forEach(playerData => {
|
||||
console.log(`${playerData.player.full_name}: ${playerData.stats_type}`);
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
### cURL Example
|
||||
|
||||
```bash
|
||||
# Get all players for Toronto Maple Leafs
|
||||
curl http://localhost:8000/api/v1/teams/TOR/players | jq '.'
|
||||
|
||||
# Get only top scorers (skaters)
|
||||
curl http://localhost:8000/api/v1/teams/TOR/players/skaters | jq '.[] | select(.stats.points > 10)'
|
||||
|
||||
# Get goalie stats
|
||||
curl http://localhost:8000/api/v1/teams/TOR/players/goalies | jq '.[] | .stats'
|
||||
```
|
||||
|
||||
## Error Handling
|
||||
|
||||
### Team Not Found (404)
|
||||
```json
|
||||
{
|
||||
"detail": "No players found for team XYZ. Please verify the team abbreviation."
|
||||
}
|
||||
```
|
||||
|
||||
### Server Error (500)
|
||||
Check server logs for detailed error information.
|
||||
|
||||
## Architecture
|
||||
|
||||
This REST API follows CLEAN architecture principles:
|
||||
|
||||
1. **Domain Layer**: Pure business entities (Player, Stats)
|
||||
2. **Application Layer**: Use cases orchestrating business logic
|
||||
3. **Infrastructure Layer**: NHL API adapter (swappable)
|
||||
4. **Presentation Layer**: FastAPI REST endpoints
|
||||
|
||||
You can swap the NHL data source by changing the dependency injection configuration in `src/presentation/api/dependencies.py` without modifying any business logic or API endpoints.
|
||||
|
||||
## Next Steps
|
||||
|
||||
- Add authentication for private endpoints
|
||||
- Implement caching for frequently requested data
|
||||
- Add filtering and sorting query parameters
|
||||
- Create endpoints for player comparisons
|
||||
- Integrate Yahoo Fantasy API data
|
||||
Reference in New Issue
Block a user