@@ -111,19 +111,23 @@ print.epidata_call <- function(epidata_call) {
111111# ' time_value and value fields or c("-direction") to return everything except
112112# ' the direction field
113113# ' @param disable_date_parsing disable automatic date parsing
114+ # ' @param return_empty boolean that allows returning an empty tibble if there is no data
115+ # ' @param timeout_seconds the maximum amount of time to wait for a response
114116# ' @return
115117# ' - For `fetch`: a tibble or a JSON-like list
116118# ' @export
117119# '
118- fetch <- function (epidata_call , fields = NULL , disable_date_parsing = FALSE ) {
120+ fetch <- function (epidata_call , fields = NULL , disable_date_parsing = FALSE , return_empty = FALSE , timeout_seconds = 30 ) {
119121 stopifnot(inherits(epidata_call , " epidata_call" ))
120122 stopifnot(is.null(fields ) || is.character(fields ))
121123 stopifnot(is.logical(disable_date_parsing ), length(disable_date_parsing ) == 1 )
124+ stopifnot(is.logical(return_empty ))
125+ stopifnot(is.numeric(timeout_seconds ))
122126
123127 if (epidata_call $ only_supports_classic ) {
124- return (fetch_classic(epidata_call , fields ))
128+ return (fetch_classic(epidata_call , fields , return_empty = return_empty , timeout_seconds = timeout_seconds ))
125129 } else {
126- return (fetch_tbl(epidata_call , fields , disable_date_parsing ))
130+ return (fetch_tbl(epidata_call , fields , disable_date_parsing , return_empty , timeout_seconds = timeout_seconds ))
127131 }
128132}
129133
@@ -136,17 +140,21 @@ fetch <- function(epidata_call, fields = NULL, disable_date_parsing = FALSE) {
136140# ' time_value and value fields or c("-direction") to return everything except
137141# ' the direction field
138142# ' @param disable_date_parsing disable automatic date parsing
143+ # ' @param return_empty boolean that allows returning an empty tibble if there is no data.
144+ # ' @param timeout_seconds the maximum amount of time to wait for a response
139145# ' @importFrom readr read_csv
140146# ' @importFrom httr stop_for_status content
141147# ' @importFrom rlang abort
142148# ' @return
143149# ' - For `fetch_tbl`: a [`tibble::tibble`]
144150# ' @importFrom tibble as_tibble
145151# ' @keywords internal
146- fetch_tbl <- function (epidata_call , fields = NULL , disable_date_parsing = FALSE ) {
152+ fetch_tbl <- function (epidata_call , fields = NULL , disable_date_parsing = FALSE , return_empty = FALSE , timeout_seconds = 30 ) {
147153 stopifnot(inherits(epidata_call , " epidata_call" ))
148154 stopifnot(is.null(fields ) || is.character(fields ))
149155 stopifnot(is.logical(disable_date_parsing ), length(disable_date_parsing ) == 1 )
156+ stopifnot(is.logical(return_empty ))
157+ stopifnot(is.numeric(timeout_seconds ))
150158
151159 if (epidata_call $ only_supports_classic ) {
152160 rlang :: abort(" This endpoint only supports the classic message format, due to a non-standard behavior. Use fetch_classic instead." ,
@@ -155,7 +163,10 @@ fetch_tbl <- function(epidata_call, fields = NULL, disable_date_parsing = FALSE)
155163 )
156164 }
157165
158- response_content <- fetch_classic(epidata_call , fields , disable_data_frame_parsing = FALSE )
166+ response_content <- fetch_classic(epidata_call , fields , disable_data_frame_parsing = FALSE , return_empty = return_empty , timeout_seconds = timeout_seconds )
167+ if (return_empty && length(response_content ) == 0 ) {
168+ return (tibble())
169+ }
159170 return (parse_data_frame(epidata_call , response_content , disable_date_parsing ) %> % as_tibble())
160171}
161172
@@ -172,32 +183,38 @@ fetch_tbl <- function(epidata_call, fields = NULL, disable_date_parsing = FALSE)
172183# ' @param disable_data_frame_parsing do not automatically cast the epidata
173184# ' output to a data frame (some endpoints return a list of lists, which is not
174185# ' a data frame)
186+ # ' @param return_empty boolean that allows returning an empty tibble if there is no data.
187+ # ' @param timeout_seconds the maximum amount of time to wait for a response
175188# ' @importFrom httr stop_for_status content http_error
176189# ' @importFrom jsonlite fromJSON
177190# ' @return
178191# ' - For `fetch_classic`: a JSON-like list
179192# ' @keywords internal
180- fetch_classic <- function (epidata_call , fields = NULL , disable_data_frame_parsing = TRUE ) {
193+ fetch_classic <- function (epidata_call , fields = NULL , disable_data_frame_parsing = TRUE , return_empty = FALSE , timeout_seconds = 30 ) {
181194 stopifnot(inherits(epidata_call , " epidata_call" ))
182195 stopifnot(is.null(fields ) || is.character(fields ))
196+ stopifnot(is.logical(return_empty ))
197+ stopifnot(is.numeric(timeout_seconds ))
183198
184- response <- request_impl(epidata_call , " classic" , fields )
199+ response <- request_impl(epidata_call , " classic" , fields , timeout_seconds )
185200 response_content <- httr :: content(response , as = " text" , encoding = " UTF-8" )
186201
187202 response_content <- jsonlite :: fromJSON(response_content , simplifyDataFrame = ! disable_data_frame_parsing )
188203
189204 # success is 1, no results is -2, truncated is 2, -1 is generic error
190205 if (response_content $ result != 1 ) {
191- rlang :: abort(paste0(" epidata error: " , response_content $ message ), " epidata_error" )
206+ if ((response_content $ result != - 2 ) && ! (return_empty )) {
207+ rlang :: abort(paste0(" epidata error: " , response_content $ message ), " epidata_error" )
208+ }
192209 }
193210 if (response_content $ message != " success" ) {
194211 rlang :: warn(paste0(" epidata warning: " , response_content $ message ), " epidata_warning" )
195212 }
196213 return (response_content $ epidata )
197214}
198215
199- fetch_debug <- function (epidata_call , format_type = " classic" , fields = NULL ) {
200- response <- request_impl(epidata_call , format_type , fields )
216+ fetch_debug <- function (epidata_call , format_type = " classic" , fields = NULL , timeout_seconds = 30 ) {
217+ response <- request_impl(epidata_call , format_type , fields , timeout_seconds )
201218 content <- httr :: content(response , " text" , encoding = " UTF-8" )
202219 content
203220}
@@ -247,13 +264,13 @@ with_base_url <- function(epidata_call, base_url) {
247264# ' HTTP errors and forwarding the HTTP body in R errors
248265# ' @importFrom httr stop_for_status content http_type
249266# ' @importFrom xml2 read_html xml_find_all xml_text
250- request_impl <- function (epidata_call , format_type , fields = NULL ) {
267+ request_impl <- function (epidata_call , format_type , fields = NULL , timeout_seconds = 30 ) {
251268 stopifnot(inherits(epidata_call , " epidata_call" ))
252269 stopifnot(format_type %in% c(" json" , " csv" , " classic" ))
253270
254271 url <- full_url(epidata_call )
255272 params <- request_arguments(epidata_call , format_type , fields )
256- response <- do_request(url , params )
273+ response <- do_request(url , params , timeout_seconds )
257274
258275 if (response $ status_code != 200 ) {
259276 # 500, 429, 401 are possible
0 commit comments