R/utils.R

#   ____________________________________________________________________________
#   Utility Functions                                                       ####

##  ............................................................................
##  General-purpose utilities                                               ####
`%!in%` <- function(a, b) !('%in%'(a, b))


##  ............................................................................
##  API Profile Options                                                     ####

#' Get and set API options
#'
#' @param endpoint The caspio subdomain endpoint
#' @param client_id The Client ID from your Web Services Profile
#' @param client_secret The Client Secret key from your Web Services Profile
#' @param access_token The temporary access token for requests
#' @param access_token The temporary access token for requests
#' @export
api_options <- settings::options_manager(endpoint = NULL,
                                         client_id = NULL,
                                         client_secret = NULL,
                                         access_token = NULL)

##  ............................................................................
##  Interface functions                                                     ####

#' Global Error Handling for Requests
#'
check_api_options <- function() {
  # Option Names
  opt_names <- names(api_options())

  # Are all options unset?
  all_unset <- purrr::map_lgl(api_options(), is.null) %>%
    all()

  # Are any options unset?
  any_unset <- purrr::map_lgl(api_options(), is.null) %>%
    any()

  # Error handling logic
  if(all_unset) {
    stop("All API Options are unset. ",
         "Use api_options([key]=[value]) to declare.")
  } else if(any_unset) {
    opt_unset <- purrr::map_lgl(api_options(), is.null) %>%
      which() %>%
      names() %>%
      glue::glue_collapse(sep = ", ")
    glue::glue("The following API Options are unset: {opt_unset}. ",
               "Use api_options([key]=[value]) to declare.") %>%
      stop()
  }
}

#' Generic HTTP status code handler
#'
#' @param resp A httr::GET response object
#' @return The requested resource response from Caspio, or an error.
#' @export
caspio_resp <- function(resp) {
  help_msg <- paste(
    "See",
    "https://howto.caspio.com/web-services-api/rest-api/error-handling/",
    "for details."
    )
  status <- resp$status
  # Error handling from HTTP request status
  if(status == 200L) {
    # Status 200: Good
    httr::content(resp, "text") %>%
      jsonlite::fromJSON() %>%
      return()
  } else if(status == 400L) {
    # Status 400: Bad Request
    stop("400--Bad Request",
         help_msg)
  } else if(status == 401L) {
    # Status 401: Unauthorized (access_token expired)
    stop("401--Unauthorized request.",
         "Please ensure your access_token is up-to-date.")
  } else if(status == 403L) {
    # Stauts 403: Forbidden
    stop("403--Forbidden",
         help_msg)
  } else if(status == 404L) {
    # Status 404: Resource not found
    stop("404--Resource not found.\n",
         "URL: ", resp$url, "\n",
         help_msg)
  } else {
    # Status not in above: unknown error, not in Caspio documentation:
    stop("Unknown response Error Code")
  }
}

#' Caspio REST API Authorization
#'
#' @export
caspio_auth <- function() {
  # Check that necessary API options are set
  api_options("endpoint", "client_id", "client_secret") %>%
    purrr::map_lgl(is.null) %>%
    any() %>%
    if(.) stop("Please set caspio endpoint, client_id, and client_secret.",
               "Use api_options([key]=[value]) to declare.")
  auth_url <- paste0("https://",
                     api_options("endpoint"),
                     ".caspio.com/oauth/token")

  # Structure the body of the request with api_options
  auth_body <- paste0(
    "grant_type=client_credentials",
    "&client_id=", api_options('client_id'),
    "&client_secret=", api_options('client_secret')
  )
  # Make and handle the request
  resp <- httr::POST(auth_url, body = auth_body)
  api_options(access_token = caspio_resp(resp)$access_token)
}



#' Caspio Bridge API wrapper and error handler
#'
#' @param resource The Caspio Bridge REST API Resource
#' @return A response object if successful, or an error message
#' @export
caspio_get <- function(resource) {
  # API-Agnostic test for an internet connection
  if(!curl::has_internet()) {
    stop("No internet connection found. Please check your connection.")
  }
  # Check that API options are set in memory
  check_api_options()

  # Perform the request
  caspio_url <- paste0("https://",
                       api_options("endpoint"),
                       ".caspio.com/rest/v2/")

  access_token <- api_options("access_token")

  resp <- httr::GET(
    paste0(caspio_url, resource),
    httr::add_headers(Authorization = paste0("bearer ", access_token))
  )
  # Parse the response
  caspio_resp(resp)
}
adam-garcia/rcaspio documentation built on July 3, 2019, 12:26 a.m.