Skip to content

Add Edge Endpoints#113

Merged
coreyjs merged 3 commits into
coreyjs:mainfrom
mattanikiej:main
Oct 31, 2025
Merged

Add Edge Endpoints#113
coreyjs merged 3 commits into
coreyjs:mainfrom
mattanikiej:main

Conversation

@mattanikiej
Copy link
Copy Markdown
Contributor

Hey I noticed that in issue #112 you wanted to add the additional Edge stats endpoints that were listed in the wiki page here that you linked in the issue as well: https://github.com/coreyjs/nhl-api-py/wiki/NHL-API-Endpoints-2025-2026.

I had some free time so I thought I'd comb through them. I got most of them in there, but the top 10 ones such as

/v1/edge/skater-shot-location-top-10/{position}/{category}/{sort-by}/now

I couldn't get to work.

Also, as for the style, I wasn't sure if you intended to create a new Edge class, which is what I did, or if you wanted these wrappers in the Stats class, so I just made them a new class. The wrappers can be very easily ported over so it's no big deal.

I know there's probably much to change here, and I wasn't part of a discussion in the issue, but I'd love to contribute, and I'll be glad to make any changes.

@coreyjs coreyjs linked an issue Oct 28, 2025 that may be closed by this pull request
@coreyjs
Copy link
Copy Markdown
Owner

coreyjs commented Oct 28, 2025

This is great, thanks! I'll check this over shortly.

As for where to put the edge stats, I was thinking about this recently and edge class does make sense, given that there are so many of them. I try to take the approach of what the end user will see, so if someone just fires up this library how do they expect to use it? What conventions make sense? Is it intuitive to use or super convoluted, can they easily get what they need in a friendly manner, etc.

So client.stats is more summary statistics with ability for complex filter queries, and client.edge is the direct edge data.

@coreyjs coreyjs added the enhancement New feature or request label Oct 28, 2025
@coreyjs coreyjs self-requested a review October 28, 2025 19:01
@mattanikiej
Copy link
Copy Markdown
Contributor Author

Yeah those were my thoughts as well for making the edge stats their own class. Let me know if you need any changes from me!

@coreyjs
Copy link
Copy Markdown
Owner

coreyjs commented Oct 29, 2025

I will try to hit this tonight after work, I am actively working on some ML stuff so this is going to be super helpful. First glance it looks good. @mattanikiej

Copy link
Copy Markdown
Owner

@coreyjs coreyjs left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just a few minor things I noticed, to make it match up with the other components. Otherwise it looks good, I like how each method is named appropriately. Thanks for putting in the work on this one.

Comment thread nhlpy/api/edge.py Outdated
# SKATER ENDPOINTS
# ========================

def skater_detail(self, player_id: int, season: int = None, game_type: int = None) -> Dict[str, Any]:
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
def skater_detail(self, player_id: int, season: int = None, game_type: int = None) -> Dict[str, Any]:
def skater_detail(self, player_id: str, season: str = None, game_type: int = None) -> Dict[str, Any]:

Let's use strings for player_id and season for this and the other methods, I found it makes using the library a bit easier. This would match things like stats.player_game_log player_game_log(self, player_id: str, season_id: str, game_type: int)

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Then update the doc string also to match.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For season, do you want me to change it to season_id? The wiki with the edge endpoints you made uses season, but I just noticed the rest of your code uses season_id. Which one would you like me to use?

Comment thread nhlpy/api/edge.py Outdated
resource = f"edge/team-landing/{season}/{game_type}"
return self.client.get(endpoint=Endpoint.API_WEB_V1, resource=resource).json()

def team_shot_speed_detail(self, team_id: int, season: int = None, game_type: int = None) -> Dict[str, Any]:
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
def team_shot_speed_detail(self, team_id: int, season: int = None, game_type: int = None) -> Dict[str, Any]:
def team_shot_speed_detail(self, team_id: str, season: str = None, game_type: int = None) -> Dict[str, Any]:

Similar to player_id I think we should also use strings here.

@coreyjs
Copy link
Copy Markdown
Owner

coreyjs commented Oct 30, 2025

One thing that is confusing me, related to the edge APIs is their use of team_id. I think team_id and franchise_id are different, but I dont think they surface team_id anymore, or at least I can't find it. I was experimenting with these endpoints and for the life of my can't figure out how they are different.

tspd = client.edge.team_skating_speed_detail(team_id=19) #buffalo
tspd2 = client.edge.team_skating_speed_detail(team_id=21) #calgary

This isn't directly related to this PR, but more about how confusing their endpoints are.

@mattanikiej
Copy link
Copy Markdown
Contributor Author

Right on man, I'll take care of these after work tonight

Copy link
Copy Markdown
Owner

@coreyjs coreyjs left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One minor thing, then good to go.

Comment thread nhlpy/api/edge.py Outdated
# SKATER ENDPOINTS
# ========================

def skater_detail(self, player_id: str, season: str = None, game_type: int = None) -> Dict[str, Any]:
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
def skater_detail(self, player_id: str, season: str = None, game_type: int = None) -> Dict[str, Any]:
def skater_detail(self, player_id: str, game_type: int = 2, season: str = None) -> Dict[str, Any]:

One more minor request I noticed the more I played around with it. Lets default game_type=2 (regular season), the reason being then when you do the check for

if season is None or game_type is None:
   ...

it can instead be

if season is None:

This alleviates some confusion where you would call

client.edge.skater_detail(player_id=1, season="20202021")

which would trigger the conditional and then return the /now version (2025-2026) instead of 2020-2021.


Lets do this for the rest of the endpoints, then its good to go. Ill aim for release in ver 3.1.0

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sounds good, just pushed the changes. Let me know if you need anything else for these endpoints.

@coreyjs coreyjs self-requested a review October 31, 2025 11:52
@coreyjs coreyjs merged commit afe9394 into coreyjs:main Oct 31, 2025
1 check failed
@coreyjs
Copy link
Copy Markdown
Owner

coreyjs commented Oct 31, 2025

closes #112 , set for release version 3.1.0

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Edge stats endpoints

2 participants