#' Get data from API.
#'
#' @param url The URL of the API. You can set this up hou you like but it usually starts with htt and ends with .com or similar.
#' @param path The second part of the URL which varies by the service you are using.
#' @param parms Named list/vector of key value pairs representing the arguments.
#' @param stringsAsFactors Return strings as factors if the data is CSV.
#' @param do.cache Save a cache of the output to be used instead of the API in case of an error, etc.
#' @param cache.path Path to save a cache to. Leave this blank and just use cache name if you wnat.
#' @param cache.name File name to use for the cache. Cache will always be a .RDS so you don't need to include the path.
#' @param use.cache.same.day Use the cache instead of calling the API again if the cache is the same day. Useful when you have limited API calls to an API.
#' @param verbose Print helpful messages about the API.
#'
#' @return List of data from the API.
#' @export
#'
#' @examples
#' #TODO
api = function(
url, path = NULL, parms = NULL,
do.cache = TRUE, cache.path = NULL, cache.name = 'api-cache', use.cache.same.day = TRUE,
verbose = TRUE,
stringsAsFactors = TRUE
){
# Same-day cache.
cache.name = gsub( '[.]RDS$', '', cache.name, ignore.case = TRUE )
if( !is.null( cache.path ) ) cache.name = paste( cache.path, cache.name, sep = '/' )
cache.name = paste0( cache.name, '.RDS' )
if( use.cache.same.day ){
icache = tryCatch({ readRDS( cache.name ) }, error = function(e){}, warning = function(w){} )
if( !is.null( icache ) ) if( icache$date == Sys.Date() ){
if( verbose ) cat( 'Same-day cache found. Returning it instead. \n' )
return( icache )
}
}
# Build our call URL.
if( !is.null(path) ) url = paste( url, path, sep = '/' )
if( !is.null( parms ) ){
pnames = names(parms)
parms = as.character(parms)
url = paste0( url, '?')
for( i in 1:length(parms) ) url = paste0( url, pnames[i], '=', parms[i], '&' )
url = gsub( '&$', '', url )
}
# Call the API. If there was an error try to use the cache.
idt = tryCatch({ tryApi( url, verbose ) }, error = function(e){
icache = tryCatch({ readRDS( cache.name ) }, function(e2){}, warning = function(w){} )
if( !is.null( icache ) ){
warning( 'Using cache due to error. Error was: \n', e )
return( icache )
}
stop( e )
} )
# Prepare return list. Save cache.
idt = list( date = Sys.Date(), data = idt )
if( do.cache ) saveRDS( idt, file = cache.name )
# Return data.
return(idt)
}
tryApi = function( url, verbose ){
url = URLencode( url )
if( verbose ) cat( 'Final URL is: ', url, '\n' )
raw.response = rawToChar( httr::GET( url )$content )
# try json.
tryCatch({
idt = jsonlite::fromJSON( raw.response )
}, error = function(e){})
# try csv.
tryCatch({
idt = data.table::fread( text = raw.response, stringsAsFactors = TRUE )
}, error = function(e){})
if( !exists('idt' ) ){
stop( 'bc::api - Response could not be parsed. Response was: \n', stringr::str_trunc( raw.response, width = 500 ) )
}
# Check common errors.
err = NULL
if( !is.null( idt[['error']] ) ){
if( !is.null(names(idt[['error']])) && !is.null( idt[['error']][['message']] ) ){
err = cc( 'API Error message: ', as.character( idt[['error']][['message']] ) )
} else {
err = cc( 'API error: \n', as.character( idt[['error']] ) )
}
}
if( !is.null(err) ) stop( as.character(err) )
return( idt )
}
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.