Skip to content

Commit 0edd537

Browse files
authored
Merge pull request #143 from R-ArcGIS/basereq
Basereq
2 parents cc48616 + 24312f4 commit 0edd537

26 files changed

+109
-243
lines changed

Diff for: DESCRIPTION

+1-1
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ Imports:
3434
terra,
3535
utils
3636
Roxygen: list(markdown = TRUE)
37-
RoxygenNote: 7.3.0
37+
RoxygenNote: 7.3.1
3838
Suggests:
3939
dbplyr,
4040
dplyr,

Diff for: NEWS.md

+3-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
# arcgislayers 0.1.0 (unreleased)
22

3+
- **Breaking**:
4+
- `token` arguments are required to be a valid `httr2_token` object (strings are not supported).
5+
- all `host` arguments are removed. Instead, the host is fetched from the `token`.
36
- Add support for `GroupLayer`s
47
- Add `arc_read()` with support for `name_repair` argument using `{vctrs}` (#108)
58
- Add `get_layer_estimates()` to retrieve estimate info such as the number of features and the extent of the layer
@@ -14,4 +17,3 @@
1417
- adds cli as an explicit import (has been implicitly imported by httr2)
1518
- repository made public
1619
- add lifecycle badges to all exported functions <https://github.com/R-ArcGIS/arcgislayers/pull/101>
17-
- Use `arcgisutils::arc_token()` to get "ARCGIS_TOKEN" environment variable. This ensures that empty strings do not cause HTTP 498 "invalid token" error.

Diff for: R/add_item.R

+27-14
Original file line numberDiff line numberDiff line change
@@ -49,8 +49,8 @@
4949
#' nc <- sf::st_read(system.file("shape/nc.shp", package = "sf"))
5050
#' x <- nc[1:5, 13]
5151
#'
52-
#' tkn <- auth_code()
53-
#' set_auth_token(tkn)
52+
#' token <- auth_code()
53+
#' set_arc_token(tkn)
5454
#'
5555
#' publish_res <- publish_layer(
5656
#' x, "North Carolina SIDS sample"
@@ -68,12 +68,19 @@ add_item <- function(
6868
categories = character(0),
6969
async = FALSE,
7070
type = "Feature Service",
71-
host = arc_host(),
7271
token = arc_token()
7372
) {
7473

74+
75+
# validate the token
76+
obj_check_token(token)
77+
78+
# fetch the host from the token
79+
host <- token[["arcgis_host"]]
80+
7581
# if async = TRUE stop
7682
# type must be feature service right now
83+
# TODO make this cli_abort()
7784
stopifnot(
7885
"`async` must be `FALSE`" = !async,
7986
"`type` must be `\"Feature Service\"`" = identical(type, "Feature Service")
@@ -87,22 +94,27 @@ add_item <- function(
8794
)
8895

8996
if (choice == 2L) {
97+
# TODO cli_abort
9098
stop("Aborting. CRS is missing.")
9199
} else {
100+
# TODO cli_warn
92101
warning("Set the CRS to prevent this interruption.\n - use `sf::st_set_crs()`")
93102
}
94103
} else if (!interactive() && is.na(sf::st_crs(x))) {
104+
# TODO cli_warn
95105
warning(
96106
"CRS is missing from `x`\nAssuming EPSG:3857."
97107
)
98108
}
99109

100110
# check if snippet is too long
111+
# TODO cli_warn
101112
if (nchar(snippet) > 2048) warning("Snippet must be 2048 or fewer characters.")
102113

103114
# check if description is too big or too many eles
104115
descrip_kb <- as.numeric(utils::object.size(description)) / 1000
105116

117+
# TODO cli_abort
106118
stopifnot(
107119
"`description` must be smaller than 64kb" = descrip_kb <= 64,
108120
"`description` must be length 1" = length(description) == 1
@@ -139,20 +151,16 @@ add_item <- function(
139151
categories = categories,
140152
type = "Feature Collection",
141153
async = async,
142-
token = token,
143154
url = host,
144155
f = "json"
145156
)
146157
)
147158

148-
149-
req <- httr2::request(req_url)
159+
req <- arc_base_req(req_url, token)
150160
req_body <- httr2::req_body_form(req, !!!req_fields)
151161
resp <- httr2::req_perform(req_body)
152-
153162
parsed <- RcppSimdJson::fparse(httr2::resp_body_string(resp))
154163
detect_errors(parsed)
155-
156164
data.frame(parsed)
157165
}
158166

@@ -170,22 +178,30 @@ publish_item <- function(
170178
user = Sys.getenv("ARCGIS_USER"),
171179
publish_params = .publish_params(),
172180
file_type = "featureCollection",
173-
host = arc_host(),
174181
token = arc_token()
175182
) {
176183

184+
# validate the token
185+
obj_check_token(token)
186+
187+
# fetch the host
188+
host <- token[["arcgis_host"]]
189+
177190
# create request URL
178191
# TODO check for trailing `/` in host (should create a `sanitize_host()`)
179192
req_url <- paste0(host, "/sharing/rest/content/users/", user, "/publish")
180193

194+
# add token and agent
195+
base_req <- arc_base_req(req_url, token)
196+
197+
181198
# create request
182199
req <- httr2::req_body_form(
183-
httr2::request(req_url),
200+
base_req,
184201
itemID = item_id,
185202
fileType = file_type,
186203
publishParameters = jsonify::to_json(publish_params, unbox = TRUE),
187204
f = "json",
188-
token = token
189205
)
190206

191207
resp <- httr2::req_perform(req)
@@ -207,7 +223,6 @@ publish_layer <- function(
207223
...,
208224
user = Sys.getenv("ARCGIS_USER"),
209225
publish_params = .publish_params(title, target_crs = sf::st_crs(x)),
210-
host = arc_host(),
211226
token = arc_token()
212227
) {
213228

@@ -218,7 +233,6 @@ publish_layer <- function(
218233
x,
219234
title,
220235
user = user,
221-
host = host,
222236
token = token,
223237
!!!adtl_args
224238
)
@@ -232,7 +246,6 @@ publish_layer <- function(
232246
item_id,
233247
user = user,
234248
publish_params = publish_params,
235-
host = host,
236249
token = token
237250
)
238251

Diff for: R/arc-add-update-delete.R

+7-13
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,8 @@ add_features <- function(
130130
indices <- chunk_indices(n, chunk_size)
131131

132132
# create the base request from the feature url
133-
req <- httr2::req_url_path_append(httr2::request(x[["url"]]), "addFeatures")
133+
base_req <- arc_base_req(x[["url"]], token)
134+
req <- httr2::req_url_path_append(base_req, "addFeatures")
134135

135136
# pre-allocate list
136137
all_reqs <- vector("list", length = lengths(indices)[1])
@@ -144,7 +145,6 @@ add_features <- function(
144145
req,
145146
features = as_esri_features(.data[start:end,]),
146147
rollbackOnFailure = rollback_on_failure,
147-
token = token,
148148
f = "json"
149149
)
150150
}
@@ -246,22 +246,19 @@ update_features <- function(
246246
.data <- .data[, present_index]
247247

248248
# create base request
249-
req <- httr2::request(
250-
paste0(x[["url"]], "/updateFeatures")
251-
)
249+
req <- arc_base_req(paste0(x[["url"]], "/updateFeatures"), token)
252250

253251
req <- httr2::req_body_form(
254252
req,
255253
# transform `.data`
256254
features = as_esri_features(.data),
257255
rollbackOnFailure = rollback_on_failure,
258-
token = token,
259256
f = "json",
260257
...
261258
)
262259

263260
resp <- httr2::req_perform(req)
264-
jsonify::from_json(httr2::resp_body_string(resp))
261+
RcppSimdJson::fparse(httr2::resp_body_string(resp))
265262
}
266263

267264

@@ -281,9 +278,7 @@ update_features <- function(
281278
#' @inheritParams prepare_spatial_filter
282279
#' @param rollback_on_failure default `TRUE`. Specifies whether the edits should be
283280
#' applied only if all submitted edits succeed.
284-
#' @param token your authorization token. By default, token is set to the
285-
#' environment variable `ARCGIS_TOKEN`. Use `set_auth_token()` to set
286-
#' `ARCGIS_TOKEN`.
281+
#' @param token default `arc_token()`. An `httr2_token`.
287282
#' @export
288283
#' @rdname modify
289284
delete_features <- function(
@@ -327,21 +322,20 @@ delete_features <- function(
327322
}
328323

329324
# https://developers.arcgis.com/rest/services-reference/enterprise/delete-features.htm
330-
req <- httr2::request(paste0(x[["url"]], "/deleteFeatures"))
325+
req <- arc_base_req(paste0(x[["url"]], "/deleteFeatures"), token)
331326

332327
req <- httr2::req_body_form(
333328
req,
334329
!!!(compact(list(where = where, objectIds = object_ids))),
335330
!!!filter_geom,
336331
f = "json",
337-
token = token,
338332
rollbackOnFailure = rollback_on_failure,
339333
...
340334
)
341335

342336
resp <- httr2::req_perform(req)
343337

344-
jsonify::from_json(httr2::resp_body_string(resp))
338+
RcppSimdJson::fparse(httr2::resp_body_string(resp))
345339
}
346340

347341

Diff for: R/arc-open.R

+10-6
Original file line numberDiff line numberDiff line change
@@ -61,12 +61,11 @@ arc_open <- function(url, token = arc_token()) {
6161

6262
stopifnot("`url` must be of length 1" = length(url) == 1)
6363

64-
# generate base request
65-
req <- httr2::request(url)
66-
6764
# extract layer metadata
68-
meta <- compact(fetch_layer_metadata(req, token))
69-
meta[["url"]] <- url # set url for later use
65+
meta <- compact(fetch_layer_metadata(url, token))
66+
67+
# set url for later use
68+
meta[["url"]] <- url
7069

7170
# layer class
7271
layer_class <- gsub("\\s", "", meta[["type"]])
@@ -103,7 +102,12 @@ arc_open <- function(url, token = arc_token()) {
103102
"ImageServer" = structure(meta, class = layer_class),
104103
"MapServer" = structure(meta, class = layer_class),
105104
"GroupLayer" = structure(meta, class = layer_class),
106-
cli::cli_abort("Unsupported service")
105+
cli::cli_abort(
106+
c(
107+
"Unsupported service type",
108+
"i"= "Please report this at {.url https://github.com/R-ArcGIS/arcgislayers/issues}"
109+
)
110+
)
107111
)
108112

109113
res

Diff for: R/arc-raster.R

+7-4
Original file line numberDiff line numberDiff line change
@@ -64,23 +64,26 @@ arc_raster <- function(
6464
# if bbox_crs is missing set to `crs`
6565
bbox_sr <- validate_crs(bbox_crs %||% crs)[[c("spatialReference", "wkid")]]
6666

67-
req <- httr2::request(paste0(x[["url"]], "/exportImage"))
67+
# create the base req
68+
burl <- paste0(x[["url"]], "/exportImage")
69+
70+
# pass that into arc_base_req() to set agent and token
71+
req <- arc_base_req(burl, token)
6872

6973
req <- httr2::req_body_form(
7074
req,
71-
# bbox = paste0(bbox, collapse = ","),
7275
bbox = paste0(c(xmin, ymin, xmax, ymax), collapse = ","),
7376
bboxSR = bbox_sr,
7477
format = format,
7578
size = paste0(c(width, height), collapse = ","),
76-
token = token,
7779
outSR = out_sr,
7880
f = "json"
7981
)
8082

83+
# fetch the response
8184
resp <- httr2::req_perform(req)
8285

83-
resp_meta <- jsonify::from_json(httr2::resp_body_string(resp))
86+
resp_meta <- RcppSimdJson::fparse(httr2::resp_body_string(resp))
8487

8588
detect_errors(resp_meta)
8689

Diff for: R/arc-select.R

+12-18
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ arc_select <- function(
6060
token = arc_token(),
6161
...
6262
) {
63+
6364
# Developer note:
6465
# For this function we extract the query object and manipulate the elements
6566
# inside of the query object to modify our request. We then splice those
@@ -135,20 +136,16 @@ collect_layer <- function(x,
135136
token = arc_token(),
136137
...,
137138
error_call = rlang::caller_env()) {
138-
check_inherits_any(
139-
x,
140-
c("FeatureLayer", "Table", "ImageServer"),
141-
call = error_call
142-
)
143-
144139
# 1. Make base request
145140
# 2. Identify necessary query parameters
146141
# 3. Figure out offsets and update query parameters
147142
# 4. Make list of requests
148143
# 5. Make requests
149144
# 6. Identify errors (if any) -- skip for now
150145
# 7. Parse:
151-
req <- httr2::request(x[["url"]])
146+
147+
# sets token and agent
148+
req <- arc_base_req(x[["url"]], token)
152149

153150
# determine if the layer can query
154151
can_query <- switch(
@@ -177,13 +174,14 @@ collect_layer <- function(x,
177174

178175
# parameter validation ----------------------------------------------------
179176
# get existing parameters
180-
query_params <- validate_params(query, token = token)
177+
query_params <- validate_params(query)
181178

182179
# Offsets -----------------------------------------------------------------
180+
# TODO make adjustable
183181
feats_per_page <- x[["maxRecordCount"]]
184182

185183
# count the number of features in a query
186-
n_feats <- count_results(req, query, token)
184+
n_feats <- count_results(req, query)
187185

188186
if (is.null(n_feats)) {
189187
cli::cli_abort(
@@ -215,13 +213,11 @@ collect_layer <- function(x,
215213
all_requests <- lapply(offsets, add_offset, req, query_params)
216214

217215
# make all requests and store responses in list
218-
all_resps <- httr2::req_perform_parallel(all_requests)
216+
all_resps <- httr2::req_perform_parallel(all_requests, on_error = "continue")
219217

220218
# identify any errors
221-
has_error <- vapply(all_resps, function(x) inherits(x, "error"), logical(1))
222-
# if (any(has_error)) {
223219
# TODO: determine how to handle errors
224-
# }
220+
has_error <- vapply(all_resps, function(x) inherits(x, "error"), logical(1))
225221

226222
# fetch the results
227223
res <- lapply(
@@ -357,9 +353,7 @@ add_offset <- function(offset, request, params) {
357353
#'
358354
#' @keywords internal
359355
#' @noRd
360-
validate_params <- function(params, token) {
361-
# set the token
362-
params[["token"]] <- token
356+
validate_params <- function(params) {
363357

364358
# if output fields are missing set to "*"
365359
if (is.null(params[["outFields"]])) params[["outFields"]] <- "*"
@@ -378,10 +372,10 @@ validate_params <- function(params, token) {
378372
}
379373

380374
# Given a query, determine how many features will be returned
381-
count_results <- function(req, query, token) {
375+
count_results <- function(req, query) {
382376
n_req <- httr2::req_body_form(
383377
httr2::req_url_path_append(req, "query"),
384-
!!!validate_params(query, token),
378+
!!!validate_params(query),
385379
returnCountOnly = "true"
386380
)
387381

0 commit comments

Comments
 (0)