R library for stubbing and setting expectations on HTTP requests.
Port of the Ruby gem webmock
The very very short version is: webmockr helps you stub HTTP requests so you don’t have to repeat yourself.
More details
You tell webmockr what HTTP request you want to match against and if it sees a request matching your criteria it doesn’t actually do the HTTP request. Instead, it gives back the same object you would have gotten back with a real request, but only with the bits it knows about. For example, we can’t give back the actual data you’d get from a real HTTP request as the request wasn’t performed.
In addition, if you set an expectation of what webmockr should return, we return that. For example, if you expect a request to return a 418 error (I’m a Teapot), then that’s what you’ll get.
What you can match against
Plus any single or combination of the following:
hello world to hello%20world)
message = hello world to message = hello%20world)
list(H1 = “value1”, content_length = 123, X_CuStOm_hEAder = “foo”)
list(h1 = “value1”, “Content-Length” = 123, “x-cuSTOM-HeAder” = “foo”)
Real HTTP requests
There’s a few scenarios to think about when using webmockr:
After doing
library(webmockr)
webmockr is loaded but not turned on. At this point webmockr doesn’t change anythning.
Once you turn on webmockr like
webmockr::enable()
webmockr will now by default not allow real HTTP requests from the http libraries that adapters are loaded for (right now only crul).
You can optionally allow real requests via webmockr_allow_net_connect(), and disallow real requests via webmockr_disable_net_connect(). You can check whether you are allowing real requests with webmockr_net_connect_allowed().
Certain kinds of real HTTP requests allowed: We don’t suppoprt this yet, but you can allow localhost HTTP requests with the allow_localhost parameter in the webmockr_configure() function.
Storing actual HTTP responses
webmockr doesn’t do that. Check out vcr
testthat via vcrfrom cran
Dev version
library(crul)
library(testthat)
# make a stub
stub_request("get", "https://httpbin.org/get") %>%
to_return(body = "success!", status = 200)
#> <webmockr stub>
#> method: get
#> uri: https://httpbin.org/get
#> with:
#> query:
#> body:
#> request_headers:
#> to_return:
#> status: 200
#> body: success!
#> response_headers:
#> should_timeout: FALSE
#> should_raise: FALSE
# check that it's in the stub registry
stub_registry()
#> <webmockr stub registry>
#> Registered Stubs
#> GET: https://httpbin.org/get | to_return: with body "success!" with status 200
# make the request
z <- crul::HttpClient$new(url = "https://httpbin.org")$get("get")
# run tests (nothing returned means it passed)
expect_is(z, "HttpResponse")
expect_equal(z$status_code, 200)
expect_equal(z$parse("UTF-8"), "success!")stub_request("get", "https://httpbin.org/get")
#> <webmockr stub>
#> method: get
#> uri: https://httpbin.org/get
#> with:
#> query:
#> body:
#> request_headers:
#> to_return:
#> status:
#> body:
#> response_headers:
#> should_timeout: FALSE
#> should_raise: FALSEx <- HttpClient$new(url = "https://httpbin.org")
x$get('get')
#> <crul response>
#> url: https://httpbin.org/get
#> request_headers:
#> User-Agent: libcurl/7.54.0 r-curl/4.2 crul/0.9.0
#> Accept-Encoding: gzip, deflate
#> Accept: application/json, text/xml, application/xml, */*
#> response_headers:
#> status: 200set return objects
stub_request("get", "https://httpbin.org/get") %>%
wi_th(
query = list(hello = "world")) %>%
to_return(status = 418)
#> <webmockr stub>
#> method: get
#> uri: https://httpbin.org/get
#> with:
#> query: hello=world
#> body:
#> request_headers:
#> to_return:
#> status: 418
#> body:
#> response_headers:
#> should_timeout: FALSE
#> should_raise: FALSEx$get('get', query = list(hello = "world"))
#> <crul response>
#> url: https://httpbin.org/get?hello=world
#> request_headers:
#> User-Agent: libcurl/7.54.0 r-curl/4.2 crul/0.9.0
#> Accept-Encoding: gzip, deflate
#> Accept: application/json, text/xml, application/xml, */*
#> response_headers:
#> params:
#> hello: world
#> status: 418stub_request("get", "https://httpbin.org/get") %>%
wi_th(query = list(hello = "world"),
headers = list('User-Agent' = 'libcurl/7.51.0 r-curl/2.6 crul/0.3.6',
'Accept-Encoding' = "gzip, deflate"))
#> <webmockr stub>
#> method: get
#> uri: https://httpbin.org/get
#> with:
#> query: hello=world
#> body:
#> request_headers: User-Agent=libcurl/7.51.0 r-cur..., Accept-Encoding=gzip, deflate
#> to_return:
#> status:
#> body:
#> response_headers:
#> should_timeout: FALSE
#> should_raise: FALSEstub_registry()
#> <webmockr stub registry>
#> Registered Stubs
#> GET: https://httpbin.org/get
#> GET: https://httpbin.org/get?hello=world | to_return: with status 418
#> GET: https://httpbin.org/get?hello=world with headers {"User-Agent":"libcurl/7.51.0 r-curl/2.6 crul/0.3.6","Accept-Encoding":"gzip, deflate"}x <- HttpClient$new(url = "https://httpbin.org")
x$get('get', query = list(hello = "world"))
#> <crul response>
#> url: https://httpbin.org/get?hello=world
#> request_headers:
#> User-Agent: libcurl/7.54.0 r-curl/4.2 crul/0.9.0
#> Accept-Encoding: gzip, deflate
#> Accept: application/json, text/xml, application/xml, */*
#> response_headers:
#> params:
#> hello: world
#> status: 418stub_request("post", "https://httpbin.org/post") %>% to_timeout()
#> <webmockr stub>
#> method: post
#> uri: https://httpbin.org/post
#> with:
#> query:
#> body:
#> request_headers:
#> to_return:
#> status:
#> body:
#> response_headers:
#> should_timeout: TRUE
#> should_raise: FALSE
x <- HttpClient$new(url = "https://httpbin.org")
x$post('post')
#> Error: Request Timeout (HTTP 408).
#> - The client did not produce a request within the time that the server was prepared to wait. The client MAY repeat the request without modifications at any later time.library(fauxpas)
stub_request("get", "https://httpbin.org/get?a=b") %>% to_raise(HTTPBadRequest)
#> <webmockr stub>
#> method: get
#> uri: https://httpbin.org/get?a=b
#> with:
#> query:
#> body:
#> request_headers:
#> to_return:
#> status:
#> body:
#> response_headers:
#> should_timeout: FALSE
#> should_raise: HTTPBadRequest
x <- HttpClient$new(url = "https://httpbin.org")
x$get('get', query = list(a = "b"))
#> Error: Bad Request (HTTP 400).
#> - The request could not be understood by the server due to malformed syntax. The client SHOULD NOT repeat the request without modifications.library(webmockr)
library(httr)
#>
#> Attaching package: 'httr'
#> The following object is masked from 'package:crul':
#>
#> handle
# turn on httr mocking
httr_mock()# no stub found
GET("https://httpbin.org/get")
#> Error: Real HTTP connections are disabled.
#> Unregistered request:
#> GET https://httpbin.org/get with headers {Accept: application/json, text/xml, application/xml, */*}
#>
#> You can stub this request with the following snippet:
#>
#> stub_request('get', uri = 'https://httpbin.org/get') %>%
#> wi_th(
#> headers = list('Accept' = 'application/json, text/xml, application/xml, */*')
#> )
#> ============================================================make a stub
stub_request('get', uri = 'https://httpbin.org/get') %>%
wi_th(
headers = list('Accept' = 'application/json, text/xml, application/xml, */*')
) %>%
to_return(status = 418, body = "I'm a teapot!!!", headers = list(im_a = "teapot"))
#> <webmockr stub>
#> method: get
#> uri: https://httpbin.org/get
#> with:
#> query:
#> body:
#> request_headers: Accept=application/json, te...
#> to_return:
#> status: 418
#> body: I'm a teapot!!!
#> response_headers: im_a=teapot
#> should_timeout: FALSE
#> should_raise: FALSEnow returns mocked response
(res <- GET("https://httpbin.org/get"))
res$status_code
#> [1] 418
res$headers
#> $im_a
#> [1] "teapot"Write to a file before mocked request
## make a temp file
f <- tempfile(fileext = ".json")
## write something to the file
cat("{\"hello\":\"world\"}\n", file = f)
readLines(f)
#> [1] "{\"hello\":\"world\"}"
## make the stub
invisible(stub_request("get", "https://httpbin.org/get") %>%
to_return(body = file(f)))
## make a request
out <- HttpClient$new("https://httpbin.org/get")$get(disk = f)
readLines(file(f))
#> [1] "{\"hello\":\"world\"}"OR - you can use mock_file() to have webmockr handle file and contents
g <- tempfile(fileext = ".json")
## make the stub
invisible(stub_request("get", "https://httpbin.org/get") %>%
to_return(body = mock_file(g, "{\"hello\":\"mars\"}\n")))
## make a request
out <- crul::HttpClient$new("https://httpbin.org/get")$get(disk = g)
readLines(out$content)
#> [1] "{\"hello\":\"world\"}"Writing to disk is supported in both crul and httr
webmockr in R doing citation(package = 'webmockr')