From 23ac9d8889f10c3da60aa53ee4624fbc0b92b16f Mon Sep 17 00:00:00 2001 From: christopher crew baker Date: Mon, 14 Jan 2019 20:02:11 -0500 Subject: [PATCH] pass detailed error message along to user if possible (closes #7) --- R/zzz.R | 30 +++++++++++++++++++++++++++++- tests/fixtures/ma_error.yml | 30 ++++++++++++++++++++++++++++++ tests/testthat/test-error-msgs.R | 12 ++++++++++++ 3 files changed, 71 insertions(+), 1 deletion(-) create mode 100644 tests/fixtures/ma_error.yml create mode 100644 tests/testthat/test-error-msgs.R diff --git a/R/zzz.R b/R/zzz.R index 5da87ff..502712c 100644 --- a/R/zzz.R +++ b/R/zzz.R @@ -17,7 +17,7 @@ ma_HTTP <- function(path, args, key, method = "GET", body = list(), GET = cli$get(path, query = args, ...), POST = cli$post(path, query = args, body = body, encode = encode, ...) ) - res$raise_for_status() + raise_for_status2(res) txt <- res$parse("UTF-8") jsonlite::fromJSON(txt, flatten = TRUE) } @@ -49,3 +49,31 @@ assert <- function(x, y) { } } } + +raise_for_status2 <- function(res) { + if (res$status_code >= 300) { + er_lst <- tryCatch( + parse_error_msg(res), + error = function(e) httpcode::http_code(res$status_code) + ) + er_msg <- sprintf( + "%s (HTTP %s)\nExplanation: %s", + res$status_code, er_lst$message, er_lst$explanation + ) + stop(er_msg, call. = FALSE) + } +} + +parse_error_msg <- function(res) { + txt <- res$parse("UTF-8") + er_vec <- unlist(jsonlite::fromJSON(txt)) + # er_vec names used to be capitilized (e.g., "Error.Code", not "error.code"). + # convert to lowercase just in case API goes back to using caps. + names(er_vec) <- tolower(names(er_vec)) + list( + # the error.code element refers to a short error message, not the HTTP + # status code + message = er_vec[["error.code"]], + explanation = er_vec[["error.message"]] + ) +} diff --git a/tests/fixtures/ma_error.yml b/tests/fixtures/ma_error.yml new file mode 100644 index 0000000..10104ad --- /dev/null +++ b/tests/fixtures/ma_error.yml @@ -0,0 +1,30 @@ +http_interactions: +- request: + method: get + uri: https://api.labs.cognitive.microsoft.com/academic/v1.0/evaluate?expr=hi-there&count=10&offset=0&attributes=Id%2CAA.AuN%2CJ.JN%2CTi%2CY%2CE%2CCC&model=latest + body: + encoding: '' + string: '' + headers: + User-Agent: libcurl/7.54.0 r-curl/3.2 crul/0.6.0 + Accept-Encoding: gzip, deflate + Accept: application/json, text/xml, application/xml, */* + Ocp-Apim-Subscription-Key: <<>> + response: + status: + status_code: '400' + message: Bad Request + explanation: Bad request syntax or unsupported method + headers: + status: HTTP/1.1 400 Bad Request + content-length: '100' + content-type: application/json + access-control-allow-origin: '*' + request-context: appId=cid-v1:7cd06f0e-6d73-46a5-9c10-4ebe681d0156 + x-powered-by: ASP.NET + date: Sat, 12 Jan 2019 03:18:16 GMT + body: + encoding: ASCII-8BIT + string: eyJFcnJvciI6eyJDb2RlIjoiQmFkIEFyZ3VtZW50IiwiTWVzc2FnZSI6IkludmFsaWQgcXVlcnkgZXhwcmVzc2lvblxyXG5QYXJhbWV0ZXIgbmFtZTogZXhwcmVzc2lvbiJ9fQ== + recorded_at: 2019-01-12 03:18:16 GMT + recorded_with: vcr/0.1.0, webmockr/0.2.6, crul/0.6.0 diff --git a/tests/testthat/test-error-msgs.R b/tests/testthat/test-error-msgs.R new file mode 100644 index 0000000..73bd01c --- /dev/null +++ b/tests/testthat/test-error-msgs.R @@ -0,0 +1,12 @@ +context("ma_error") + +test_that("Detailed error messages are provided when possible", { + skip_on_cran() + + vcr::use_cassette("ma_error", { + expect_error( + ma_search(query = "hi-there"), + "query" + ) + }, preserve_exact_body_bytes = TRUE) +})