-
Notifications
You must be signed in to change notification settings - Fork 17
/
zzz.R
89 lines (80 loc) · 2.76 KB
/
zzz.R
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
#' @importFrom methods is
#' @importFrom utils URLencode
#' @importFrom dplyr bind_rows
#' @importFrom dplyr as_tibble
#' @importFrom httr GET
#' @importFrom httr add_headers
#' @importFrom httr content
#' @importFrom httr stop_for_status
#' @importFrom httr http_error
#' @importFrom jsonlite fromJSON
ebird_compact <- function(x) Filter(Negate(is.null), x)
ebase <- function() 'https://ebird.org/ws2.0/'
get_key <- function(key = NULL) {
if (!is.null(key)) return(key)
key <- Sys.getenv("EBIRD_KEY")
if (!nzchar(key)) {
stop(
"You must provide an API key from eBird.
You can pass it to the 'key' argument or store it as
an environment variable called EBIRD_KEY in your .Renviron file.
If you don't have a key, you can obtain one from:
https://ebird.org/api/keygen.", call. = FALSE
)
}
key
}
ebird_GET <- function(url, args, key = NULL, ...){
tt <- GET(URLencode(url),
query = ebird_compact(args),
add_headers("X-eBirdApiToken" = get_key(key)), # removed config = add_headers(...
# to allow config = to be specified in ...
...)
# Testing for errors and providing informative error messages
# if request contains error information, provide that error message
if (http_error(tt) & !is.raw(content(tt))) stop(paste(content(tt)$error[[1]], collapse = " -- "))
# if API key is invalid the API gives error 403 but doesn't provide content so there isn't an error message.
# Thus error message is specified below.
if (tt$status_code == 403 & is.raw(content(tt))) {
stop_for_status(tt, task = "connect to eBird API. Invalid token")
}
stop_for_status(tt) # in case any cases fall through the cracks above
ss <- content(tt, as = "text", encoding = "UTF-8")
json <- fromJSON(ss, FALSE)
if (tt$status_code > 202) {
warning(sprintf("%s", json[[1]]['errorMsg']))
NA
} else {
if (!is.list(json)) {
return(NA)
} else {
json <- lapply(json, function(x) lapply(x, function(a) {
if (length(a) == 0) {
NA
} else if (length(a) > 1) {
paste0(a, collapse = ",")
} else {
if (is(a, "list")) {
a[[1]]
} else {
a
}
}
}))
# at least one API call returns a json structure where each element
# contains a single, unnamed string. This case isn't handled by as_tibble()
# so detect and deal with it separately.
unnamedSingleValues <- all(sapply(
json,
function(x) {
length(x) == 1 & length(names(x)) == 0
}
))
if (unnamedSingleValues) {
as_tibble(unlist(json))
} else {
bind_rows(lapply(json, as_tibble))
}
}
}
}