Skip to content

Instantly share code, notes, and snippets.

@tcash21
Forked from Btibert3/README.md
Last active December 9, 2015 01:17
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save tcash21/44667f7b8578cc8e061e to your computer and use it in GitHub Desktop.
Save tcash21/44667f7b8578cc8e061e to your computer and use it in GitHub Desktop.
Testing stattleship, weird error

About

Updated the queryAPI and created a new function, stattle that wraps it and makes walking easier. jsonlite is great, but I started to bump into some issues with dplyr::bind_rows. Right now these two functions play nice together, but needs to be further tested.

Load/Install

## source the functions
devtools::source_url('https://gist.githubusercontent.com/tcash21/44667f7b8578cc8e061e/raw/fdac84a0a445e448427cc3557e8c9393ce1fa470/queryAPI.r')
devtools::source_url('https://gist.githubusercontent.com/tcash21/44667f7b8578cc8e061e/raw/69503a2dcd69a5a2fc5021c25a7bbf86c1080aa9/stattle.r')

Requirements

We will handle these better shortly, but the code requires:

  • dplyr
  • httr
  • jsonlite

Basic Usage

league = "nba"
sport = "basketball"
q_body = list(player_id="nba-rajon-rondo")
ep = "game_logs"
rondo.logs <- stattle(TOKEN, sport=sport, league=league, ep=ep, query=q_body, version=1, walk=T,verbose=T)

The rondo.logs object returns a list of lists. In the example above, there were two hits to the API, so length(rondo.logs) is 2. Nested below each of these parent lists are the data.

Collapse the data into a dataframe.

plus.minus <- unlist(lapply(rondo.logs, function(x) x$game_log$plus_minus))
turnovers <- unlist(lapply(rondo.logs, function(x) x$game_log$turnovers))
game.name <- unlist(lapply(rondo.logs, function(x) x$games$name))
d <- data.frame(plus_minus = plus.minus, turnovers=turnovers, game=game.name)

Get all NBA triple doubles this season

league = "nba"
sport = "basketball"
ep = "stats"
q_body=list(stat="triple_double")
tripdubs = stattle(TOKEN, sport=sport, league=league, ep=ep, query=q_body, version=1, walk=T)

TODO

  • put this into a more formal package
  • leverage way better version control
#' Interface with the Stattleship API
#'
#' A simple, generic function to query data from the API
#'
#' @param token character. A valid token for the API
#' @param sport character. The sport, such as hockey, basketball, football
#' @param league character. NHL, NBA, etc.
#' @param ep character. The endpoint
#' @param query A list that defines the query parameters
#' @param version The API version. Current version is 1.
#' @param walk logical. NOT YET IMPLEMENTED
#' @param page numeric. The page number to request
#' @param verbose logical. For debugging, returns response and parsed response.
#'
#' @examples
#' \dontrun{
#' TOKEN = "aklsjdlfkajsfdas"
#' results = queryAPI(TOKEN,
#' sport="hockey",
#' query=list(player_id="akjasdf")
#' version = 1,
#' ep = "stats",
#' verbose = F)
#'
#' @export
queryAPI = function(token,
sport="hockey",
league = "nhl",
ep="stats",
query=list(),
version=1,
walk=F,
page=NA,
verbose=F) {
## TODO: walk the results if > 20 entries
## TODO: test to validate data types
## TODO: best practices on walking the data? Have # entries paramter?
## packages : doesnt feel like this is the right way to do it
library(httr)
## build the URL and the endpoint
URL = sprintf("https://www.stattleship.com/%s/%s/%s", sport, league, ep)
## the accept parameters. Is there a better way to do this?
ACCEPT = sprintf("application/vnd.stattleship.com; version=%d", version)
## if page is supplied, add it to the list
if (!is.na(page) & is.numeric(page) & page >= 1) {
query = c(query, page=page)
}
## test the body to see if it is a list and has values
## if not, just return an empty list
## todo: test to ensure that query is a list if !is.na
## get the request from the API
resp = GET(URL,
add_headers(Authorization =TOKEN,
Accept = ACCEPT,
`Content-Type`="application/json"),
query=query)
## walk the content if true
## convert response to text first, do not use baseline httr::content default
api_response = content(resp, as="text")
## use jsonlite::fromJSON
api_response = jsonlite::fromJSON(api_response)
## if verbose = T, return a list that includes the parsed results
## and the original request
if (verbose) {
api_response = list(response = resp,
api_json = api_response)
}
## return the data
return(api_response)
}
stattle = function(token,
sport="hockey",
league = "nhl",
ep="stats",
query=list(),
version=1,
walk=F,
page=NA,
verbose=F) {
## if na, set page to 1 for consistency
if (is.na(page)) page = 1
## if page is supplied, add it to the list
if (!is.na(page) & is.numeric(page) & page >= 1) {
query = c(query, page=page)
}
print("Making initial API request")
## get the first request
tmp = queryAPI(TOKEN, sport, league, ep, query, verbose=T)
## simple alert
if (tmp$response$status_code != 200) {
message("API response was something other than 200")
}
## create the response list
response = list()
## set the original parsed response to the first element
response[[1]] = tmp$api_json
## if walk, parse here and send into respose[[i]]
## NOT FINISHED -- below is under dev
if (walk) {
## check to see if paging is necessary
total_results = as.numeric(tmp$response$headers$total)
rpp = as.numeric(tmp$response$headers$`per-page`)
pages = ceiling(total_results / rpp)
## the first page was already retrievedd, only care 2+
if (pages >= 2) {
for (p in 2:pages) {
print(paste0("Retrieving results from page ", p, " of ", pages))
tmp_p = queryAPI(TOKEN, sport, league, ep, query=query, page=p, verbose=T)
## check to make sure 200
if (tmp$response$status_code != 200) {
message("the pages>2 loop requested a page that was not 200")
}
## add as an element into the response container
response[[p]] = tmp_p$api_json
}
}#endif(pages)
}#endif(walk)
## return the list of data results
## list of lists
return(response)
}
@Btibert3
Copy link

Btibert3 commented Dec 9, 2015

I had 2nd devtools::source_url throw an error on me for a bad file??? Wierd. This worked on my machine, so not sure if it is setting error or whatever random bug it could be.

devtools::source_url('https://gist.githubusercontent.com/tcash21/44667f7b8578cc8e061e/raw/fdac84a0a445e448427cc3557e8c9393ce1fa470/queryAPI.r')
devtools::source_url('https://gist.githubusercontent.com/tcash21/44667f7b8578cc8e061e/raw/c081e8bdbc31b55534d1624b19c939c5773bac3c/stattle.r')

As I type that, I wonder if I had an old browser page open and a change was pushed. That could have been on my end ...

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