webmockr

knitr::opts_chunk$set(
  comment = "#>",
  collapse = TRUE,
  warning = FALSE
)

cran checks Project Status: Active - The project has reached a stable, usable state and is being actively developed. R-CMD-check codecov rstudio mirror downloads cran version

R library for stubbing and setting expectations on HTTP requests.

Port of the Ruby gem webmock

How it works in detail


Features

Supported HTTP libraries

Install

from cran

install.packages("webmockr")

Dev version

# install.packages("pak")
pak::pak("ropensci/webmockr")
library(webmockr)

Enable webmockr

webmockr::enable()

Inside a test framework

library(crul)
library(testthat)

# make a stub
stub_request("get", "https://httpbin.org/get") %>%
   to_return(body = "success!", status = 200)

# check that it's in the stub registry
stub_registry()

# 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_registry_clear()

Outside a test framework

library(crul)

Stubbed request based on uri only and with the default response

stub_request("get", "https://httpbin.org/get")
x <- HttpClient$new(url = "https://httpbin.org")
x$get('get')

set return objects

stub_request("get", "https://httpbin.org/get") %>%
  wi_th(
    query = list(hello = "world")) %>%
    to_return(status = 418)
x$get('get', query = list(hello = "world"))

Stubbing requests based on method, uri and query params

stub_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"))
stub_registry()
x <- HttpClient$new(url = "https://httpbin.org")
x$get('get', query = list(hello = "world"))

Stubbing requests and set expectation of a timeout

stub_request("post", "https://httpbin.org/post") %>% to_timeout()
x <- HttpClient$new(url = "https://httpbin.org")
x$post('post')

Stubbing requests and set HTTP error expectation

library(fauxpas)
stub_request("get", "https://httpbin.org/get?a=b") %>% to_raise(HTTPBadRequest)
x <- HttpClient$new(url = "https://httpbin.org")
x$get('get', query = list(a = "b"))

httr integration

library(webmockr)
library(httr)

# 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"))

now returns mocked response

(res <- GET("https://httpbin.org/get"))
res$status_code
#> [1] 418
res$headers
#> $im_a
#> [1] "teapot"

httr2 integration

library(webmockr)
library(httr2)

# turn on httr2 mocking
enable()
# no stub found
req <- request("https://hb.opencpu.org/get")
req_perform(req)
#> Error: Real HTTP connections are disabled.
#> Unregistered request:
#>   GET https://hb.opencpu.org/get
#> 
#> You can stub this request with the following snippet:
#> 
#>    stub_request('get', uri = 'https://hb.opencpu.org/get')
#> ============================================================

make a stub

stub_request('get', uri = 'https://hb.opencpu.org/get') %>%
  to_return(status = 418, body = "I'm a teapot!!!", headers = list(im_a = "teapot"))

now returns mocked response

req <- request("https://hb.opencpu.org/get")
res <- req_perform(req)
res
res$status_code
#> [1] 418
res$headers
#> <httr2_headers/list>
#> im_a: teapot

Writing to disk

Write to a file before mocked request

stub_registry_clear()
request_registry_clear()
## make a temp file
f <- tempfile(fileext = ".json")
## write something to the file
cat("{\"hello\":\"world\"}\n", file = f)
readLines(f)
## 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))

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)

Writing to disk is supported in crul, httr, and httr2

Many requests in a row

e.g., many redirects, then a final successful request

webmockr::enable()
library(crul)
library(fauxpas)

z <- stub_request("get", "https://httpbin.org/get")
to_return(z, status = 200, body = "foobar", headers = list(a = 5))
to_return(z, status = 200, body = "bears", headers = list(b = 6))
to_raise(z, HTTPBadRequest)
z

con <- crul::HttpClient$new(url = "https://httpbin.org")
# the first to_return()
first <- con$get("get")
first
first$parse("UTF-8")
# the second to_return()
second <- con$get("get")
second
second$parse("UTF-8")
# the third to_return() - fails as specified
third <- con$get("get")

Note that subsequent requests past the number of responses given with to_return()/etc. simply gives the last response you specified. Although if you set a to_timeout or to_raise this feature won't happen since you fail out.

Contributors

Meta



ropensci/webmockr documentation built on June 14, 2025, 1:24 p.m.