Fix NHL API adapter to handle actual API response structures

Corrected data parsing issues discovered during testing:

Teams Endpoint:
- Fixed get_all_teams to handle list response (not dict with "data" key)
- Corrected team name parsing to avoid duplication
- Properly extract city from full team name using common_name
- Fixed division and conference extraction from nested dict structures

Stats Endpoints:
- Fixed game log parsing to handle list response (not dict with "gameLog" key)
- Applied fix to both skater and goalie stats methods

Testing Results:
- Successfully retrieves all 32 NHL teams with correct names
- Team lookup by abbreviation working correctly
- Division and conference filtering operational
- Player roster retrieval functional (28 players)
- Player stats aggregation working (verified with Sammy Blais)

All adapter methods now correctly transform NHL API responses to domain entities.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Michael Simard
2025-11-23 22:33:44 -06:00
parent 6d8d51f698
commit 28169863df

View File

@@ -110,11 +110,12 @@ class NHLPlayerAdapter(PlayerRepository):
player_id=player_id, season_id=season_id, game_type=2
)
if not game_log or "gameLog" not in game_log:
# The API returns a list directly
if not game_log or not isinstance(game_log, list):
return None
# Aggregate stats from game log
return self._aggregate_skater_stats(player_id, game_log["gameLog"])
return self._aggregate_skater_stats(player_id, game_log)
except Exception as e:
logger.error(f"Error fetching skater stats for player {player_id}: {e}")
@@ -136,11 +137,12 @@ class NHLPlayerAdapter(PlayerRepository):
player_id=player_id, season_id=season_id, game_type=2
)
if not game_log or "gameLog" not in game_log:
# The API returns a list directly
if not game_log or not isinstance(game_log, list):
return None
# Aggregate stats from game log
return self._aggregate_goalie_stats(player_id, game_log["gameLog"])
return self._aggregate_goalie_stats(player_id, game_log)
except Exception as e:
logger.error(f"Error fetching goalie stats for player {player_id}: {e}")
@@ -395,11 +397,12 @@ class NHLTeamAdapter(TeamRepository):
try:
teams_data = self.client.teams.teams()
if not teams_data or "data" not in teams_data:
# The API returns a list directly, not a dict with "data" key
if not teams_data or not isinstance(teams_data, list):
return []
teams = []
for team_data in teams_data["data"]:
for team_data in teams_data:
team = self._transform_team_data(team_data)
if team:
teams.append(team)
@@ -430,25 +433,39 @@ class NHLTeamAdapter(TeamRepository):
def _transform_team_data(self, team_data: Dict[str, Any]) -> Optional[NHLTeam]:
"""Transforms NHL API team data to domain NHLTeam entity."""
try:
team_name = team_data.get("fullName", "") or team_data.get("teamName", {}).get("default", "")
city_name = team_data.get("placeName", {}).get("default", "")
# API returns structure: {name, common_name, abbr, division:{name}, conference:{name}}
# name = "Colorado Avalanche", common_name = "Avalanche"
full_name = team_data.get("name", "")
common_name = team_data.get("common_name", "")
# Handle team name that might include city
if not city_name and " " in team_name:
parts = team_name.rsplit(" ", 1)
if len(parts) == 2:
# Extract city and team name
# The full_name includes city, common_name is just the team name
if " " in full_name and common_name:
# Split to get city (everything except the common_name at the end)
city_name = full_name.replace(common_name, "").strip()
team_name = common_name
elif " " in full_name:
# Fallback: split on last space
parts = full_name.rsplit(" ", 1)
city_name = parts[0]
team_name = parts[1]
else:
city_name = ""
team_name = full_name
# Extract division and conference from nested dicts
division_data = team_data.get("division", {})
conference_data = team_data.get("conference", {})
return NHLTeam(
id=str(team_data.get("id", "")),
id=str(team_data.get("franchise_id", "")),
name=team_name,
abbreviation=team_data.get("triCode", ""),
abbreviation=team_data.get("abbr", ""),
city=city_name,
division=team_data.get("divisionName", ""),
conference=team_data.get("conferenceName", ""),
division=division_data.get("name", "") if isinstance(division_data, dict) else "",
conference=conference_data.get("name", "") if isinstance(conference_data, dict) else "",
venue_name=None, # Not provided in basic team data
is_active=team_data.get("isActive", True),
is_active=True, # All teams in current API are active
)
except Exception as e:
logger.error(f"Error transforming team data: {e}")