API Example Using R

# This data frame contains the coordinate pairs for the vertices of the polygon
# for an AOI. You can get an equivalent data frame from an sf polygon object
# using sf::st_coordinates(). Note that the first and last coordinates are
# identical in order to close the polygon.
aoi_vertex_coords <- data.frame(X = c(-106.416024,
                                      -106.157845,
                                      -106.146859,
                                      -106.328133,
                                      -106.388558,
                                      -106.454476,
                                      -106.416024),
                                Y = c(44.086577,
                                      44.228451,
                                      44.471990,
                                      44.417086,
                                      44.318914,
                                      44.193015,
                                      44.086577))

# This creates the coordinate strings formatted for use in a geoJSON using the
# data frame of coordinates. The expected format for a coordinate pair is
# "[-106.454476,44.193015]". This could be achieved with an apply() but using
# mutate() from the package dplyr is more readable.
aoi_vertex_coords <- dplyr::mutate(.data = aoi_vertex_coords,
                                   # This creates a new variable with the strings
                                   # for each row.
                                   coordinate_string = paste0("[", X, ",", Y, "]"))


# These are the pieces of the geoJSON string that go before and after the
# coordinates. In the postcoordinate string, you may define "mask" as true to
# ignore cropland, development, and open water or false to include those.
# Note that in order for this to work, the strings defining the geoJSON *must*
# use quotation marks internally, so the strings themselves need to be wrapped
# in aprostrophes, e.g. '{"type":"Feature"}' and not "{'type':'Feature'}".
geojson_precoordinate_string <-'{"type":"Feature",
                                 "geometry": {"geodesic":false,
                                              "type":"Polygon",
                                              "coordinates":[['
geojson_postcoordinate_string <- ']]},
                                   "properties": {"mask":true,
                                                  "year":null}
                                  }'

# The components can be assembled into a single geoJSON string.
# The coordinate strings in the data frame need to be collapsed into a single
# string where each pair is separated by a comma.
aoi_geojson <- paste0(geojson_precoordinate_string,
                      paste(aoi_vertex_coords[["coordinate_string"]],
                            collapse = ","),
                      geojson_postcoordinate_string)

# Using httr::RETRY() will let R make multiple attempts to retrieve the data
# before giving up. Importantly, the verb argument must be "POST", the URL must
# point to the correct API endpoint for the data you want, config should at
# least specify that the desired return format is JSON, and the body argument
# needs to be the geoJSON string constructed for the AOI.
rap_json <- httr::RETRY(verb = "POST",
                        url = "https://us-central1-rap-data-365417.cloudfunctions.net/production16dayV3",
                        config = httr::content_type_json(),
                        body = aoi_geojson)

# httr::content() will convert the returned JSON into more conventional R
# objects: nested lists containing the various kinds of values in the JSON.
rap_obj <- httr::content(x = rap_json,
                         as = "parsed")

# The returned and parsed object will be a list. One of the values in the list
# will be another list named "properties" which contains yet another list of
# each of the rows in the returned dataset, including the variable names as the
# first vector in the list. In this case, the data are for 16-day production.
returned_data_raw_list <- rap_obj$properties$production16day


# There's no "correct" way way to convert the list into a data frame. One of the
# more straightforward is by turning each list of values in the list into a
# data frame then combining those with dplyr:bind_rows().
returned_data_raw_list <- lapply(X = returned_data_raw_list[2:length(returned_data_raw_list)],
                                 variable_names = returned_data_raw_list[[1]],
                                 FUN = function(X, variable_names){
                                   # The current values need the variable names,
                                   # so this makes sure that variable_names is a
                                   # vector before assigning them to the current
                                   # row's values which are called X within the
                                   # lapply().
                                   names(X) <- unlist(variable_names)
                                   # Make a wide-format data frame out of the
                                   # current values by binding them column-wise
                                   # which results in a single data frame with
                                   # correctly-named variables thanks to the
                                   # naming of X above.
                                   dplyr::bind_cols(X)
                                 })
returned_data_raw_dataframe <- dplyr::bind_rows(returned_data_raw_list)

# The data returned will include some values that need to be adjusted before
# using, which can be accomplished with dplyr::mutate().
returned_data <- dplyr::mutate(.data = returned_data_raw_dataframe,
                               # Convert the date from a character string to a 
                               # value of class "date".
                               date = as.Date(date),
                               # Make sure the year is numeric because it may be
                               # a character string.
                               year = as.numeric(year),
                               # Make sure the day of the year is also numeric
                               # and adjust so that the highest value is 365 and
                               # not 366.
                               doy = as.numeric(doy) - 1,
                               # The rest of the variables should be numeric and
                               # rounded to 3 decimal places. Additionally, any
                               # values of -99 should be considered NA values.
                               # Using dplyr::across() here applies the
                               # replacement, conversion, and rounding to all
                               # variables after the first three, i.e., after
                               # date, year, and doy.
                               dplyr::across(.cols = -c(1:3),
                                             .fns = ~ replace(x = .x,
                                                              list = .x == -99,
                                                              values = NA) |>
                                               as.numeric(x = _) |>
                                               round(x = _,
                                                     digits = 3)))