Title: Record 'HTTP' Calls to Disk
Description: Record test suite 'HTTP' requests and replays them during future runs. A port of the Ruby gem of the same name (https://github.com/vcr/vcr/). Works by hooking into the 'webmockr' R package for matching 'HTTP' requests by various rules ('HTTP' method, 'URL', query parameters, headers, body, etc.), and then caching real 'HTTP' responses on disk in 'cassettes'. Subsequent 'HTTP' requests matching any previous requests in the same 'cassette' use a cached 'HTTP' response.
Version: 1.7.0
URL: https://github.com/ropensci/vcr/, https://books.ropensci.org/http-testing/, https://docs.ropensci.org/vcr/
BugReports: https://github.com/ropensci/vcr/issues
License: MIT + file LICENSE
Encoding: UTF-8
Language: en-US
LazyData: true
VignetteBuilder: knitr
Imports: crul (≥ 0.8.4), httr, httr2, webmockr (≥ 0.8.0), urltools, yaml, R6, base64enc, rprojroot
Suggests: roxygen2 (≥ 7.2.1), jsonlite, testthat, knitr, rmarkdown, desc, crayon, cli, curl, withr, webfakes
X-schema.org-applicationCategory: Web
X-schema.org-keywords: http, https, API, web-services, curl, mock, mocking, http-mocking, testing, testing-tools, tdd
X-schema.org-isPartOf: https://ropensci.org
RoxygenNote: 7.3.2
NeedsCompilation: no
Packaged: 2025-03-07 18:32:27 UTC; sckott
Author: Scott Chamberlain ORCID iD [aut, cre], Aaron Wolen ORCID iD [aut], Maëlle Salmon ORCID iD [aut], Daniel Possenriede ORCID iD [aut], rOpenSci ROR ID [fnd]
Maintainer: Scott Chamberlain <myrmecocystus@gmail.com>
Repository: CRAN
Date/Publication: 2025-03-10 10:10:02 UTC

vcr: Record 'HTTP' Calls to Disk

Description

Record test suite 'HTTP' requests and replays them during future runs. A port of the Ruby gem of the same name (https://github.com/vcr/vcr/). Works by hooking into the 'webmockr' R package for matching 'HTTP' requests by various rules ('HTTP' method, 'URL', query parameters, headers, body, etc.), and then caching real 'HTTP' responses on disk in 'cassettes'. Subsequent 'HTTP' requests matching any previous requests in the same 'cassette' use a cached 'HTTP' response.

Backstory

A Ruby gem of the same name (VCR, https://github.com/vcr/vcr) was created many years ago and is the original. Ports in many languages have been done. Check out that GitHub repo for all the details on how the canonical version works.

Main functions

The use_cassette function is most likely what you'll want to use. It sets the cassette you want to record to, inserts the cassette, and then ejects the cassette, recording the interactions to the cassette.

Instead, you can use insert_cassette, but then you have to make sure to use eject_cassette.

vcr configuration

vcr_configure is the function to use to set R session wide settings. See it's manual file for help.

Record modes

See recording for help on record modes.

Request matching

See request-matching for help on the many request matching options.

Async

As of crul v1.5, vcr will work for async http requests with crul. httr does not do async requests, and httr2 async plumbing does not have any hooks for mocking via webmockr or recording real requests via this package

Author(s)

Maintainer: Scott Chamberlain myrmecocystus@gmail.com (ORCID)

Authors:

Other contributors:

See Also

Useful links:


Coerce names, etc. to cassettes

Description

Coerce names, etc. to cassettes

Coerce to a cassette path

Usage

as.cassette(x, ...)

as.cassettepath(x)

Arguments

x

Input, a cassette name (character), or something that can be coerced to a cassette

...

further arguments passed on to cassettes() or [read_cassette_meta()

Value

a cassette of class Cassette

Examples

## Not run: 
vcr_configure(dir = tempfile())
insert_cassette("foobar")
cassettes(on_disk = FALSE)
cassettes(on_disk = TRUE)
as.cassette("foobar", on_disk = FALSE)
eject_cassette() # eject the current cassette

# cleanup
unlink(file.path(tempfile(), "foobar.yml"))

## End(Not run)

Cassette handler

Description

Main R6 class that is called from the main user facing function use_cassette()

Value

an object of class Cassette

Points of webmockr integration

Public fields

name

(character) cassette name

record

(character) record mode

manfile

(character) cassette file path

recorded_at

(character) date/time recorded at

serialize_with

(character) serializer to use (yaml|json)

serializer

(character) serializer to use (yaml|json)

persist_with

(character) persister to use (FileSystem only)

persister

(character) persister to use (FileSystem only)

match_requests_on

(character) matchers to use default: method & uri

re_record_interval

(numeric) the re-record interval

tag

ignored, not used right now

tags

ignored, not used right now

root_dir

root dir, gathered from vcr_configuration()

update_content_length_header

(logical) Whether to overwrite the Content-Length header

allow_playback_repeats

(logical) Whether to allow a single HTTP interaction to be played back multiple times

allow_unused_http_interactions

(logical) ignored, not used right now

exclusive

(logical) ignored, not used right now

preserve_exact_body_bytes

(logical) Whether to base64 encode the bytes of the requests and responses

args

(list) internal use

http_interactions_

(list) internal use

new_recorded_interactions

(list) internal use

clean_outdated_http_interactions

(logical) Should outdated interactions be recorded back to file

to_return

(logical) internal use

cassette_opts

(list) various cassette options

Methods

Public methods


Method new()

Create a new Cassette object

Usage
Cassette$new(
  name,
  record,
  serialize_with,
  persist_with,
  match_requests_on,
  re_record_interval,
  tag,
  tags,
  update_content_length_header,
  allow_playback_repeats,
  allow_unused_http_interactions,
  exclusive,
  preserve_exact_body_bytes,
  clean_outdated_http_interactions
)
Arguments
name

The name of the cassette. vcr will sanitize this to ensure it is a valid file name.

record

The record mode. Default: "once". In the future we'll support "once", "all", "none", "new_episodes". See recording for more information

serialize_with

(character) Which serializer to use. Valid values are "yaml" (default), the only one supported for now.

persist_with

(character) Which cassette persister to use. Default: "file_system". You can also register and use a custom persister.

match_requests_on

List of request matchers to use to determine what recorded HTTP interaction to replay. Defaults to ⁠["method", "uri"]⁠. The built-in matchers are "method", "uri", "headers" and "body" ("host" and "path" not supported yet, but should be in a future version)

re_record_interval

(numeric) When given, the cassette will be re-recorded at the given interval, in seconds.

tag, tags

tags ignored, not used right now

update_content_length_header

(logical) Whether or not to overwrite the Content-Length header of the responses to match the length of the response body. Default: FALSE

allow_playback_repeats

(logical) Whether or not to allow a single HTTP interaction to be played back multiple times. Default: FALSE.

allow_unused_http_interactions

(logical) ignored, not used right now

exclusive

(logical) ignored, not used right now

preserve_exact_body_bytes

(logical) Whether or not to base64 encode the bytes of the requests and responses for this cassette when serializing it. See also preserve_exact_body_bytes in vcr_configure(). Default: FALSE

clean_outdated_http_interactions

(logical) Should outdated interactions be recorded back to file. Default: FALSE

Returns

A new Cassette object


Method print()

print method for Cassette objects

Usage
Cassette$print(x, ...)
Arguments
x

self

...

ignored


Method call_block()

run code

Usage
Cassette$call_block(...)
Arguments
...

pass in things to be evaluated

Returns

various


Method eject()

ejects the current cassette

Usage
Cassette$eject()
Returns

self


Method file()

get the file path for the cassette

Usage
Cassette$file()
Returns

character


Method recording()

is the cassette in recording mode?

Usage
Cassette$recording()
Returns

logical


Method is_empty()

is the cassette on disk empty

Usage
Cassette$is_empty()
Returns

logical


Method originally_recorded_at()

timestamp the cassette was originally recorded at

Usage
Cassette$originally_recorded_at()
Returns

POSIXct date


Method serializable_hash()

Get a list of the http interactions to record + recorded_with

Usage
Cassette$serializable_hash()
Returns

list


Method interactions_to_record()

Get the list of http interactions to record

Usage
Cassette$interactions_to_record()
Returns

list


Method merged_interactions()

Get interactions to record

Usage
Cassette$merged_interactions()
Returns

list


Method up_to_date_interactions()

Cleans out any old interactions based on the re_record_interval and clean_outdated_http_interactions settings

Usage
Cassette$up_to_date_interactions(interactions)
Arguments
interactions

list of http interactions, of class HTTPInteraction

Returns

list of interactions to record


Method should_re_record()

Should re-record interactions?

Usage
Cassette$should_re_record()
Returns

logical


Method should_stub_requests()

Is record mode NOT "all"?

Usage
Cassette$should_stub_requests()
Returns

logical


Method should_remove_matching_existing_interactions()

Is record mode "all"?

Usage
Cassette$should_remove_matching_existing_interactions()
Returns

logical


Method storage_key()

Get the serializer path

Usage
Cassette$storage_key()
Returns

character


Method raw_cassette_bytes()

Get character string of entire cassette; bytes is a misnomer

Usage
Cassette$raw_cassette_bytes()
Returns

character


Method make_dir()

Create the directory that holds the cassettes, if not present

Usage
Cassette$make_dir()
Returns

no return; creates a directory recursively, if missing


Method deserialized_hash()

get http interactions from the cassette via the serializer

Usage
Cassette$deserialized_hash()
Returns

list


Method previously_recorded_interactions()

get all previously recorded interactions

Usage
Cassette$previously_recorded_interactions()
Returns

list


Method write_recorded_interactions_to_disk()

write recorded interactions to disk

Usage
Cassette$write_recorded_interactions_to_disk()
Returns

nothing returned


Method record_http_interaction()

record an http interaction (doesn't write to disk)

Usage
Cassette$record_http_interaction(x)
Arguments
x

a crul, httr, or httr2 response object, with the request at ⁠$request⁠

Returns

nothing returned


Method any_new_recorded_interactions()

Are there any new recorded interactions?

Usage
Cassette$any_new_recorded_interactions()
Returns

logical


Method make_args()

make list of all options

Usage
Cassette$make_args()
Returns

nothing returned


Method write_metadata()

write metadata to the cassette

Usage
Cassette$write_metadata()
Returns

nothing returned


Method http_interactions()

make HTTPInteractionList object, assign to http_interactions_ var

Usage
Cassette$http_interactions()
Returns

nothing returned


Method make_http_interaction()

Make an HTTPInteraction object

Usage
Cassette$make_http_interaction(x)
Arguments
x

A crul, httr, or httr2 response object, with the request at ⁠$request⁠

Returns

an object of class HTTPInteraction


Method serialize_to_crul()

Make a crul response object

Usage
Cassette$serialize_to_crul()
Returns

a crul response


Method clone()

The objects of this class are cloneable with this method.

Usage
Cassette$clone(deep = FALSE)
Arguments
deep

Whether to make a deep clone.

See Also

vcr_configure(), use_cassette(), insert_cassette()

Examples

## Not run: 
library(vcr)
vcr_configure(dir = tempdir())

res <- Cassette$new(name = "bob")
res$file()
res$originally_recorded_at()
res$recording()
res$serializable_hash()
res$eject()
res$should_remove_matching_existing_interactions()
res$storage_key()
res$match_requests_on

# record all requests
res <- Cassette$new("foobar", record = "all")
res$eject()

# cleanup
unlink(file.path(tempdir(), c("bob.yml", "foobar.yml")))

library(vcr)
vcr_configure(dir = tempdir())
res <- Cassette$new(name = "jane")
library(crul)
# HttpClient$new("https://hb.opencpu.org")$get("get")

## End(Not run)

List cassettes, get current cassette, etc.

Description

List cassettes, get current cassette, etc.

Usage

cassettes(on_disk = TRUE, verb = FALSE)

current_cassette()

cassette_path()

Arguments

on_disk

(logical) Check for cassettes on disk + cassettes in session (TRUE), or check for only cassettes in session (FALSE). Default: TRUE

verb

(logical) verbose messages

Details

Examples

vcr_configure(dir = tempdir())

# list all cassettes
cassettes()
cassettes(on_disk = FALSE)

# list the currently active cassette
insert_cassette("stuffthings")
current_cassette()
eject_cassette()

cassettes()
cassettes(on_disk = FALSE)

# list the path to cassettes
cassette_path()
vcr_configure(dir = file.path(tempdir(), "foo"))
cassette_path()

vcr_configure_reset()

Check cassette names

Description

Check cassette names

Usage

check_cassette_names(
  pattern = "test-",
  behavior = "stop",
  allowed_duplicates = NULL
)

Arguments

pattern

(character) regex pattern for file paths to check. this is done inside of ⁠tests/testthat/⁠. default: "test-"

behavior

(character) "stop" (default) or "warning". if "warning", we use immediate.=TRUE so the warning happens at the top of your tests rather than you seeing it after tests have run (as would happen by default)

allowed_duplicates

(character) cassette names that can be duplicated

Details

Cassette names:

vcr::check_cassette_names() is meant to be run during your tests, from a ⁠helper-*.R⁠ file inside the tests/testthat directory. It only checks that cassette names are not duplicated. Note that if you do need to have duplicated cassette names you can do so by using the allowed_duplicates parameter in check_cassette_names(). A helper function check_cassette_names() runs inside insert_cassette() that checks that cassettes do not have: spaces, file extensions, unaccepted characters (slashes).


An HTTP request as prepared by the crul package

Description

The object is a list, and is the object that is passed on to webmockr and vcr instead of routing through crul as normal. Used in examples/tests.

Format

A list


Eject a cassette

Description

Eject a cassette

Usage

eject_cassette(
  cassette = NULL,
  options = list(),
  skip_no_unused_interactions_assertion = NULL
)

Arguments

cassette

(character) a single cassette names to eject; see name parameter definition in insert_cassette() for cassette name rules

options

(list) a list of options to apply to the eject process

skip_no_unused_interactions_assertion

(logical) If TRUE, this will skip the "no unused HTTP interactions" assertion enabled by the allow_unused_http_interactions = FALSE cassette option. This is intended for use when your test has had an error, but your test framework has already handled it - IGNORED FOR NOW

Value

The ejected cassette if there was one

See Also

use_cassette(), insert_cassette()

Examples

vcr_configure(dir = tempdir())
insert_cassette("hello")
(x <- current_cassette())

# by default does current cassette
x <- eject_cassette()
x
# can also select by cassette name
# eject_cassette(cassette = "hello")

File system persister

Description

The only built-in cassette persister. Persists cassettes to the file system.

Details

Private Methods

storage_location()

Get storage location

absolute_path_to_file()

Get absolute path to the storage_location

Public fields

file_name

(character) the file name, not whole path

write_fxn

(character) fxn to use for writing to disk

content

(character) content to record to a cassette

path

(character) storage directory for cassettes

write2disk

(character) write to disk or make a new FileSystem

Methods

Public methods


Method new()

Create a new FileSystem object

Usage
FileSystem$new(
  file_name = NULL,
  write_fxn = NULL,
  content = NULL,
  path = NULL,
  write2disk = FALSE
)
Arguments
file_name

(character) the file name, not whole path

write_fxn

(character) fxn to use for writing to disk

content

(character) content to record to a cassette

path

(character) storage directory for cassettes

write2disk

(logical) write to disk or just make a new FileSystem object. Default: FALSE

Returns

A new FileSystem object


Method get_cassette()

Gets the cassette for the given storage key (file name)

Usage
FileSystem$get_cassette(file_name = NULL)
Arguments
file_name

(character) the file name, not whole path

Returns

named list, from yaml::yaml.load_file


Method is_empty()

Checks if a cassette is empty or not

Usage
FileSystem$is_empty()
Returns

logical


Method set_cassette()

Sets the cassette for the given storage key (file name)

Usage
FileSystem$set_cassette(file_name = NULL, content)
Arguments
file_name

(character) the file name, not whole path

content

(character) content to record to a cassette

Returns

no return; writes to disk


Method clone()

The objects of this class are cloneable with this method.

Usage
FileSystem$clone(deep = FALSE)
Arguments
deep

Whether to make a deep clone.


Hooks class

Description

Helps define new hooks, hold hooks, and accessors to get and use hooks.

Details

Private Methods

make_hook(x, plac, fun)

Make a hook. - x (character) Hook name - plac Placement, one of "start" or "end" - fun a function/callback

Public fields

hooks

intenal use

Methods

Public methods


Method invoke_hook()

invoke a hook

Usage
Hooks$invoke_hook(hook_type, args)
Arguments
hook_type

(character) Hook name

args

(named list) Args passed when invoking a hook

Returns

executes hook


Method clear_hooks()

clear all hooks

Usage
Hooks$clear_hooks()
Returns

no return


Method define_hook()

define a hook

Usage
Hooks$define_hook(hook_type, fun, prepend = FALSE)
Arguments
hook_type

(character) Hook name

fun

A function

prepend

(logical) Whether to prepend or add to the end of the string. Default: FALSE

Returns

no return; defines hook internally


Method clone()

The objects of this class are cloneable with this method.

Usage
Hooks$clone(deep = FALSE)
Arguments
deep

Whether to make a deep clone.


Get the http interactions of the current cassette

Description

Get the http interactions of the current cassette

Usage

http_interactions()

Value

object of class HTTPInteractionList if there is a current cassette in use, or NullList if no cassette in use

Examples

## Not run: 
vcr_configure(dir = tempdir())
insert_cassette("foo_bar")
webmockr::webmockr_allow_net_connect()
library(crul)
cli <- crul::HttpClient$new("https://hb.opencpu.org/get")
one <- cli$get(query = list(a = 5))
z <- http_interactions()
z
z$interactions
z$used_interactions
# on eject, request written to the cassette
eject_cassette("foo_bar")

# insert cassette again
insert_cassette("foo_bar")
# now interactions will be present 
z <- http_interactions()
z$interactions
z$used_interactions
invisible(cli$get(query = list(a = 5)))
z$used_interactions

# cleanup
unlink(file.path(tempdir(), "foo_bar.yml"))

## End(Not run)

HTTPInteraction class

Description

object holds request and response objects

Details

Methods

to_hash()

Create a hash from the HTTPInteraction object

from_hash(hash)

Create a HTTPInteraction object from a hash

Public fields

request

A Request class object

response

A VcrResponse class object

recorded_at

(character) Time http interaction recorded at

Methods

Public methods


Method new()

Create a new HTTPInteraction object

Usage
HTTPInteraction$new(request, response, recorded_at)
Arguments
request

A Request class object

response

A VcrResponse class object

recorded_at

(character) Time http interaction recorded at

Returns

A new HTTPInteraction object


Method to_hash()

Create a hash from the HTTPInteraction object

Usage
HTTPInteraction$to_hash()
Returns

a named list


Method from_hash()

Create a HTTPInteraction object from a hash

Usage
HTTPInteraction$from_hash(hash)
Arguments
hash

a named list

Returns

a new HttpInteraction object


Method clone()

The objects of this class are cloneable with this method.

Usage
HTTPInteraction$clone(deep = FALSE)
Arguments
deep

Whether to make a deep clone.

Examples

## Not run: 
# make the request
library(vcr)
url <- "https://hb.opencpu.org/post"
body <- list(foo = "bar")
cli <- crul::HttpClient$new(url = url)
res <- cli$post(body = body)

# build a Request object
(request <- Request$new("POST", uri = url,
  body = body, headers = res$response_headers))
# build a VcrResponse object
(response <- VcrResponse$new(
   res$status_http(),
   res$response_headers,
   res$parse("UTF-8"),
   res$response_headers$status))

# make HTTPInteraction object
(x <- HTTPInteraction$new(request = request, response = response))
x$recorded_at
x$to_hash()

# make an HTTPInteraction from a hash with the object already made
x$from_hash(x$to_hash())

# Make an HTTPInteraction from a hash alone
my_hash <- x$to_hash()
HTTPInteraction$new()$from_hash(my_hash)

## End(Not run)

HTTPInteractionList class

Description

keeps track of all HTTPInteraction objects

Details

Private Methods

has_unused_interactions()

Are there any unused interactions? returns boolean

matching_interaction_index_for()

asdfadf

matching_used_interaction_for(request)

asdfadfs

interaction_matches_request(request, interaction)

Check if a request matches an interaction (logical)

from_hash()

Get a hash back.

request_summary(z)

Get a request summary (character)

response_summary(z)

Get a response summary (character)

Public fields

interactions

(list) list of interaction class objects

request_matchers

(character) vector of request matchers

allow_playback_repeats

whether to allow playback repeats

parent_list

A list for empty objects, see NullList

used_interactions

(list) Interactions that have been used

Methods

Public methods


Method new()

Create a new HTTPInteractionList object

Usage
HTTPInteractionList$new(
  interactions,
  request_matchers,
  allow_playback_repeats = FALSE,
  parent_list = NullList$new(),
  used_interactions = list()
)
Arguments
interactions

(list) list of interaction class objects

request_matchers

(character) vector of request matchers

allow_playback_repeats

whether to allow playback repeats or not

parent_list

A list for empty objects, see NullList

used_interactions

(list) Interactions that have been used. That is, interactions that are on disk in the current cassette, and a request has been made that matches that interaction

Returns

A new HTTPInteractionList object


Method response_for()

Check if there's a matching interaction, returns a response object

Usage
HTTPInteractionList$response_for(request)
Arguments
request

The request from an object of class HTTPInteraction


Method has_interaction_matching()

Check if has a matching interaction

Usage
HTTPInteractionList$has_interaction_matching(request)
Arguments
request

The request from an object of class HTTPInteraction

Returns

logical


Method has_used_interaction_matching()

check if has used interactions matching a given request

Usage
HTTPInteractionList$has_used_interaction_matching(request)
Arguments
request

The request from an object of class HTTPInteraction

Returns

logical


Method remaining_unused_interaction_count()

Number of unused interactions

Usage
HTTPInteractionList$remaining_unused_interaction_count()
Returns

integer


Method assert_no_unused_interactions()

Checks if there are no unused interactions left.

Usage
HTTPInteractionList$assert_no_unused_interactions()
Returns

various


Method clone()

The objects of this class are cloneable with this method.

Usage
HTTPInteractionList$clone(deep = FALSE)
Arguments
deep

Whether to make a deep clone.

Examples

## Not run: 
vcr_configure(
 dir = tempdir(),
 record = "once"
)

# make interactions
## make the request
### turn off mocking
crul::mock(FALSE)
url <- "https://hb.opencpu.org/post"
cli <- crul::HttpClient$new(url = url)
res <- cli$post(body = list(a = 5))

## request
(request <- Request$new("POST", url, list(a = 5), res$headers))
## response
(response <- VcrResponse$new(
   res$status_http(),
   res$response_headers,
   res$parse("UTF-8"),
   res$response_headers$status))
## make an interaction
(inter <- HTTPInteraction$new(request = request, response = response))

# make an interactionlist
(x <- HTTPInteractionList$new(
   interactions = list(inter),
   request_matchers = vcr_configuration()$match_requests_on
))
x$interactions
x$request_matchers
x$parent_list
x$parent_list$response_for()
x$parent_list$has_interaction_matching()
x$parent_list$has_used_interaction_matching()
x$parent_list$remaining_unused_interaction_count()
x$used_interactions
x$allow_playback_repeats
x$interactions
x$response_for(request)

## End(Not run)

Insert a cassette to record HTTP requests

Description

Insert a cassette to record HTTP requests

Usage

insert_cassette(
  name,
  record = NULL,
  match_requests_on = NULL,
  update_content_length_header = FALSE,
  allow_playback_repeats = FALSE,
  serialize_with = NULL,
  persist_with = NULL,
  preserve_exact_body_bytes = NULL,
  re_record_interval = NULL,
  clean_outdated_http_interactions = NULL
)

Arguments

name

The name of the cassette. vcr will check this to ensure it is a valid file name. Not allowed: spaces, file extensions, control characters (e.g., ⁠\n⁠), illegal characters ('/', '?', '<', '>', '\', ':', '*', '|', and '\"'), dots alone (e.g., '.', '..'), Windows reserved words (e.g., 'com1'), trailing dots (can cause problems on Windows), names longer than 255 characters. See section "Cassette names"

record

The record mode (default: "once"). See recording for a complete list of the different recording modes.

match_requests_on

List of request matchers to use to determine what recorded HTTP interaction to replay. Defaults to ⁠["method", "uri"]⁠. The built-in matchers are "method", "uri", "host", "path", "headers", "body" and "query"

update_content_length_header

(logical) Whether or not to overwrite the Content-Length header of the responses to match the length of the response body. Default: FALSE

allow_playback_repeats

(logical) Whether or not to allow a single HTTP interaction to be played back multiple times. Default: FALSE.

serialize_with

(character) Which serializer to use. Valid values are "yaml" (default) and "json". Note that you can have multiple cassettes with the same name as long as they use different serializers; so if you only want one cassette for a given cassette name, make sure to not switch serializers, or clean up files you no longer need.

persist_with

(character) Which cassette persister to use. Default: "file_system". You can also register and use a custom persister.

preserve_exact_body_bytes

(logical) Whether or not to base64 encode the bytes of the requests and responses for this cassette when serializing it. See also preserve_exact_body_bytes in vcr_configure(). Default: FALSE

re_record_interval

(integer) How frequently (in seconds) the cassette should be re-recorded. default: NULL (not re-recorded)

clean_outdated_http_interactions

(logical) Should outdated interactions be recorded back to file? default: FALSE

Details

Cassette names:

vcr::check_cassette_names() is meant to be run during your tests, from a ⁠helper-*.R⁠ file inside the tests/testthat directory. It only checks that cassette names are not duplicated. Note that if you do need to have duplicated cassette names you can do so by using the allowed_duplicates parameter in check_cassette_names(). A helper function check_cassette_names() runs inside insert_cassette() that checks that cassettes do not have: spaces, file extensions, unaccepted characters (slashes).

Value

an object of class Cassette

Cassette options

Default values for arguments controlling cassette behavior are inherited from vcr's global configuration. See vcr_configure() for a complete list of options and their default settings. You can override these options for a specific cassette by changing an argument's value to something other than NULL when calling either insert_cassette() or use_cassette().

See Also

use_cassette(), eject_cassette()

Examples

## Not run: 
library(vcr)
library(crul)
vcr_configure(dir = tempdir())
webmockr::webmockr_allow_net_connect()

(x <- insert_cassette(name = "leo5"))
current_cassette()
x$new_recorded_interactions
x$previously_recorded_interactions()
cli <- crul::HttpClient$new(url = "https://hb.opencpu.org")
cli$get("get")
x$new_recorded_interactions # 1 interaction
x$previously_recorded_interactions() # empty
webmockr::stub_registry() # not empty
# very important when using inject_cassette: eject when done
x$eject() # same as eject_cassette("leo5")
x$new_recorded_interactions # same, 1 interaction
x$previously_recorded_interactions() # now not empty
## stub_registry now empty, eject() calls webmockr::disable(), which
## calls the disable method for each of crul and httr adadapters,
## which calls webmockr's remove_stubs() method for each adapter
webmockr::stub_registry()

# cleanup
unlink(file.path(tempdir(), "leo5.yml"))

## End(Not run)

The JSON serializer

Description

class with methods for serializing via jsonlite

Super class

vcr::Serializer -> JSON

Methods

Public methods


Method new()

Create a new JSON object

Usage
JSON$new(path = NULL)
Arguments
path

(character) full path to the yaml file

Returns

A new JSON object


Method serialize()

Serializes the given hash using internal fxn write_json

Usage
JSON$serialize(x, path, bytes)
Arguments
x

(list) the object to serialize

path

(character) the file path

bytes

(logical) whether to preserve exact body bytes or not

Returns

(character) the json string to write to disk


Method deserialize()

Deserializes the content at the file path using jsonlite::fromJSON

Usage
JSON$deserialize(cassette)
Arguments
cassette

the current cassette object so it's properties can be retrieved

Returns

(list) the deserialized object, an R list


Method clone()

The objects of this class are cloneable with this method.

Usage
JSON$clone(deep = FALSE)
Arguments
deep

Whether to make a deep clone.


Turn vcr on and off, check on/off status, and turn off for a given http call

Description

Turn vcr on and off, check on/off status, and turn off for a given http call

Usage

turned_off(..., ignore_cassettes = FALSE)

turn_on()

turned_on()

turn_off(ignore_cassettes = FALSE)

Arguments

...

Any block of code to run, presumably an http request

ignore_cassettes

(logical) Controls what happens when a cassette is inserted while vcr is turned off. If TRUE is passed, the cassette insertion will be ignored; otherwise an error will be raised. Default: FALSE

Details

Sometimes you may need to turn off vcr, either for individual function calls, individual test blocks, whole test files, or for the entire package. The following attempts to break down all the options.

vcr has the following four exported functions:

Instead of using the above four functions, you could use environment variables to achieve the same thing. This way you could enable/disable vcr in non-interactive environments such as continuous integration, Docker containers, or running R non-interactively from the command line. The full set of environment variables vcr uses, all of which accept only TRUE or FALSE:

turned_off

turned_off() lets you temporarily make a real HTTP request without completely turning vcr off, unloading it, etc.

What happens internally is we turn off vcr, run your code block, then on exit turn vcr back on - such that vcr is only turned off for the duration of your code block. Even if your code block errors, vcr will be turned back on due to use of on.exit(turn_on())

library(vcr)
library(crul)
turned_off({
  con <- HttpClient$new(url = "https://httpbin.org/get")
  con$get()
})
#> <crul response>
#>   url: https://httpbin.org/get
#>   request_headers:
#>     User-Agent: libcurl/7.54.0 r-curl/4.3 crul/0.9.0
#>     Accept-Encoding: gzip, deflate
#>     Accept: application/json, text/xml, application/xml, */*
#>   response_headers:
#>     status: HTTP/1.1 200 OK
#>     date: Fri, 14 Feb 2020 19:44:46 GMT
#>     content-type: application/json
#>     content-length: 365
#>     connection: keep-alive
#>     server: gunicorn/19.9.0
#>     access-control-allow-origin: *
#>     access-control-allow-credentials: true
#>   status: 200

turn_off/turn_on

turn_off() is different from turned_off() in that turn_off() is not aimed at a single call block, but rather it turns vcr off for the entire package. turn_off() does check first before turning vcr off that there is not currently a cassette in use. turn_off() is meant to make R ignore vcr::insert_cassette() and vcr::use_cassette() blocks in your test suite - letting the code in the block run as if they were not wrapped in vcr code - so that all you have to do to run your tests with cached requests/responses AND with real HTTP requests is toggle a single R function or environment variable.

library(vcr)
vcr_configure(dir = tempdir())
# real HTTP request works - vcr is not engaged here
crul::HttpClient$new(url = "https://eu.httpbin.org/get")$get()
# wrap HTTP request in use_cassette() - vcr is engaged here
use_cassette("foo_bar", {
  crul::HttpClient$new(url = "https://eu.httpbin.org/get")$get()
})
# turn off & ignore cassettes - use_cassette is ignored, real HTTP request made
turn_off(ignore_cassettes = TRUE)
use_cassette("foo_bar", {
  crul::HttpClient$new(url = "https://eu.httpbin.org/get")$get()
})
# if you turn off and don't ignore cassettes, error thrown
turn_off(ignore_cassettes = FALSE)
use_cassette("foo_bar", {
  res2=crul::HttpClient$new(url = "https://eu.httpbin.org/get")$get()
})
# vcr back on - now use_cassette behaves as before
turn_on()
use_cassette("foo_bar3", {
  res2=crul::HttpClient$new(url = "https://eu.httpbin.org/get")$get()
})

turned_on

turned_on() does what it says on the tin - it tells you if vcr is turned on or not.

library(vcr)
turn_on()
turned_on()
## [1] TRUE
turn_off()
## vcr turned off; see ?turn_on to turn vcr back on
turned_on()
## [1] FALSE

Environment variables

The VCR_TURN_OFF environment variable can be used within R or on the command line to turn off vcr. For example, you can run tests for a package that uses vcr, but ignore any use_cassette/insert_cassette usage, by running this on the command line in the root of your package:

VCR_TURN_OFF=true Rscript -e "devtools::test()"

Or, similarly within R:

Sys.setenv(VCR_TURN_OFF = TRUE)
devtools::test()

The VCR_TURNED_OFF and VCR_IGNORE_CASSETTES environment variables can be used in combination to achieve the same thing as VCR_TURN_OFF:

VCR_TURNED_OFF=true VCR_IGNORE_CASSETTES=true Rscript -e "devtools::test()"

Examples

## Not run: 
vcr_configure(dir = tempdir())

turn_on()
turned_on()
turn_off()

# turn off for duration of a block
library(crul)
turned_off({
 res <- HttpClient$new(url = "https://hb.opencpu.org/get")$get()
})
res

# turn completely off
turn_off()
library(webmockr)
crul::mock()
# HttpClient$new(url = "https://hb.opencpu.org/get")$get(verbose = TRUE)
turn_on()

## End(Not run)

Cassette persisters

Description

Keeps track of the cassette persisters in a hash-like object

Usage

persister_fetch(x = "FileSystem", file_name)

Details

There's only one option: FileSystem Private Methods

persister_get()

Gets and sets a named persister

Public fields

persisters

(list) internal use, holds persister object

name

(character)

Methods

Public methods


Method new()

Create a new Persisters object

Usage
Persisters$new(persisters = list(), name = "FileSystem")
Arguments
persisters

(list) a list

name

(character) Persister name, only option right now is "FileSystem"

Returns

A new Persisters object


Method clone()

The objects of this class are cloneable with this method.

Usage
Persisters$clone(deep = FALSE)
Arguments
deep

Whether to make a deep clone.

Examples

(aa <- Persisters$new())
aa$name
aa$persisters
yaml_serializer <- aa$persisters$new()
yaml_serializer

Are real http connections allowed?

Description

Are real http connections allowed?

Usage

real_http_connections_allowed()

Value

boolean, TRUE if real HTTP requests allowed; FALSE if not

Examples

real_http_connections_allowed()

vcr recording options

Description

vcr recording options

Details

Record modes dictate under what circumstances http requests/responses are recorded to cassettes (disk). Set the recording mode with the parameter record in the use_cassette() and insert_cassette() functions.

once

The once record mode will:

It is similar to the new_episodes record mode, but will prevent new, unexpected requests from being made (i.e. because the request URI changed or whatever).

once is the default record mode, used when you do not set one.

none

The none record mode will:

This is useful when your code makes potentially dangerous HTTP requests. The none record mode guarantees that no new HTTP requests will be made.

new_episodes

The new_episodes record mode will:

It is similar to the once record mode, but will always record new interactions, even if you have an existing recorded one that is similar (but not identical, based on the match_request_on option).

all

The all record mode will:

This can be temporarily used to force vcr to re-record a cassette (i.e. to ensure the responses are not out of date) or can be used when you simply want to log all HTTP requests.


The request of an HTTPInteraction

Description

object that handled all aspects of a request

Public fields

method

(character) http method

uri

(character) a uri

scheme

(character) scheme (http or https)

host

(character) host (e.g., stuff.org)

path

(character) path (e.g., foo/bar)

query

(character) query params, named list

body

(character) named list

headers

(character) named list

skip_port_stripping

(logical) whether to strip the port

hash

(character) a named list - internal use

opts

(character) options - internal use

disk

(logical) xx

fields

(various) request body details

output

(various) request output details, disk, memory, etc

policies

(various) http policies, used in httr2 only

Methods

Public methods


Method new()

Create a new Request object

Usage
Request$new(
  method,
  uri,
  body,
  headers,
  opts,
  disk,
  fields,
  output,
  policies,
  skip_port_stripping = FALSE
)
Arguments
method

(character) the HTTP method (i.e. head, options, get, post, put, patch or delete)

uri

(character) request URI

body

(character) request body

headers

(named list) request headers

opts

(named list) options internal use

disk

(boolean), is body a file on disk

fields

(various) post fields

output

(various) output details

policies

(various) http policies, used in httr2 only

skip_port_stripping

(logical) whether to strip the port. default: FALSE

Returns

A new Request object


Method to_hash()

Convert the request to a list

Usage
Request$to_hash()
Returns

list


Method from_hash()

Convert the request to a list

Usage
Request$from_hash(hash)
Arguments
hash

a list

Returns

a new Request object


Method clone()

The objects of this class are cloneable with this method.

Usage
Request$clone(deep = FALSE)
Arguments
deep

Whether to make a deep clone.

Examples

url <- "https://hb.opencpu.org/post"
body <- list(foo = "bar")
headers <- list(
  `User-Agent` = "libcurl/7.54.0 r-curl/3.2 crul/0.5.2",
  `Accept-Encoding` = "gzip, deflate",
  Accept = "application/json, text/xml, application/xml, */*"
)

(x <- Request$new("POST", url, body, headers))
x$body
x$method
x$uri
x$host
x$path
x$headers
h <- x$to_hash()
x$from_hash(h)

request and response summary methods

Description

request and response summary methods

Usage

request_summary(request, request_matchers = "")

response_summary(response)

Arguments

request

a Request object

request_matchers

(character) a vector of matchers. Default: ""

response

a VcrResponse object

Details

By default, method and uri are included in the request summary - if body and/or headers are specified in request_matchers, then they are also included

HTTP status code and response body are included in the response summary. The response body is truncated to a max of 80 characters

In response_summary() we use gsub with useBytes=TRUE to avoid problems sometimes seen with multibyte strings - this shouldn't affect your data/etc. as this is only for printing a summary of the response

Value

character string, of either request or response

Examples

# request
url <- "https://hb.opencpu.org"
body <- list(foo = "bar")
headers <- list(
  `User-Agent` = "r-curl/3.2",
  `Accept-Encoding` = "gzip, deflate",
  Accept = "application/json"
)

(x <- Request$new("POST", url, body, headers))
request_summary(request = x)
request_summary(request = x, c('method', 'uri'))
request_summary(request = x, c('method', 'uri', 'body'))
request_summary(request = x, c('method', 'uri', 'headers'))
request_summary(request = x, c('method', 'uri', 'body', 'headers'))

# response
status <- list(status_code = 200, message = "OK",
  explanation = "Request fulfilled, document follows")
headers <- list(
  status = "HTTP/1.1 200 OK",
  connection = "keep-alive",
  date = "Tue, 24 Apr 2018 04:46:56 GMT"
)
response_body <- 
"{\"args\": {\"q\": \"stuff\"}, \"headers\": {\"Accept\": \"text/html\"}}\n"
(x <- VcrResponse$new(status, headers,
   response_body, "HTTP/1.1 200 OK"))
response_summary(x)

## with binary body
# path <- "tests/testthat/png_eg.rda"
# load(path)
# (x <- VcrResponse$new(status, headers, png_eg, "HTTP/1.1 200 OK"))
# response_summary(x)

vcr request matching

Description

There are a number of options, some of which are on by default, some of which can be used together, and some alone.

Details

To match previously recorded requests, vcr has to try to match new HTTP requests to a previously recorded one. By default, we match on HTTP method (e.g., GET) and URI (e.g., ⁠http://foo.com⁠), following Ruby’s VCR gem.

You can customize how we match requests with one or more of the following options, some of which are on by default, some of which can be used together, and some alone.

You can set your own options by tweaking the match_requests_on parameter in use_cassette():

library(vcr)
use_cassette(name = "foo_bar", {
    cli$post("post", body = list(a = 5))
  }, 
  match_requests_on = c('method', 'headers', 'body')
)

Matching

headers
library(crul)
library(vcr)
cli <- crul::HttpClient$new("https://httpbin.org/get", 
  headers = list(foo = "bar"))
use_cassette(name = "nothing_new", {
    one <- cli$get()
  }, 
  match_requests_on = 'headers'
)
cli$headers$foo <- "stuff"
use_cassette(name = "nothing_new", {
    two <- cli$get()
  }, 
  match_requests_on = 'headers'
)
one$request_headers
two$request_headers

RequestHandler

Description

Base handler for http requests, deciding whether a request is stubbed, to be ignored, recordable, or unhandled

Details

Private Methods

request_type(request)

Get the request type

externally_stubbed()

just returns FALSE

should_ignore()

should we ignore the request, depends on request ignorer infrastructure that's not working yet

has_response_stub()

Check if there is a matching response stub in the http interaction list

get_stubbed_response()

Check for a response and get it

request_summary(request)

get a request summary

on_externally_stubbed_request(request)

on externally stubbed request do nothing

on_ignored_request(request)

on ignored request, do something

on_recordable_request(request)

on recordable request, record the request

on_unhandled_request(request)

on unhandled request, run UnhandledHTTPRequestError

Public fields

request_original

original, before any modification

request

the request, after any modification

vcr_response

holds VcrResponse object

stubbed_response

the stubbed response

cassette

the cassette holder

Methods

Public methods


Method new()

Create a new RequestHandler object

Usage
RequestHandler$new(request)
Arguments
request

The request from an object of class HttpInteraction

Returns

A new RequestHandler object


Method handle()

Handle the request (request given in ⁠$initialize()⁠)

Usage
RequestHandler$handle()
Returns

handles a request, outcomes vary


Method clone()

The objects of this class are cloneable with this method.

Usage
RequestHandler$clone(deep = FALSE)
Arguments
deep

Whether to make a deep clone.

Examples

## Not run: 
# record mode: once
vcr_configure(
 dir = tempdir(),
 record = "once"
)

data(crul_request)
crul_request$url$handle <- curl::new_handle()
crul_request
x <- RequestHandler$new(crul_request)
# x$handle()

# record mode: none
vcr_configure(
 dir = tempdir(),
 record = "none"
)
data(crul_request)
crul_request$url$handle <- curl::new_handle()
crul_request
insert_cassette("testing_record_mode_none", record = "none")
#file.path(vcr_c$dir, "testing_record_mode_none.yml")
x <- RequestHandlerCrul$new(crul_request)
# x$handle()
crul_request$url$url <- "https://api.crossref.org/works/10.1039/c8sm90002g/"
crul_request$url$handle <- curl::new_handle()
z <- RequestHandlerCrul$new(crul_request)
# z$handle()
eject_cassette("testing_record_mode_none")

## End(Not run)

RequestHandlerCrul

Description

Methods for the crul package, building on RequestHandler

Super class

vcr::RequestHandler -> RequestHandlerCrul

Methods

Public methods

Inherited methods

Method clone()

The objects of this class are cloneable with this method.

Usage
RequestHandlerCrul$clone(deep = FALSE)
Arguments
deep

Whether to make a deep clone.

Examples

## Not run: 
vcr_configure(
 dir = tempdir(),
 record = "once"
)

data(crul_request)
crul_request$url$handle <- curl::new_handle()
crul_request
x <- RequestHandlerCrul$new(crul_request)
# x$handle()

# body matching
library(vcr)
library(crul)
vcr_configure(dir = tempdir(), log = TRUE,
 log_opts = list(file = file.path(tempdir(), "vcr.log")))
cli <- HttpClient$new(url = "https://hb.opencpu.org")

## testing, same uri and method, changed body in 2nd block
use_cassette(name = "apple7", {
  resp <- cli$post("post", body = list(foo = "bar"))
}, match_requests_on = c("method", "uri", "body"))
## should error, b/c record="once"
if (interactive()) {
  use_cassette(name = "apple7", {
    resp <- cli$post("post", body = list(foo = "bar"))
    resp2 <- cli$post("post", body = list(hello = "world"))
  }, match_requests_on = c("method", "uri", "body"))
}
cas <- insert_cassette(name = "apple7", 
  match_requests_on = c("method", "uri", "body"))
resp2 <- cli$post("post", body = list(foo = "bar"))
eject_cassette("apple7")

## testing, same body, changed method in 2nd block
if (interactive()) {
use_cassette(name = "apple8", {
  x <- cli$post("post", body = list(hello = "world"))
}, match_requests_on = c("method", "body"))
use_cassette(name = "apple8", {
  x <- cli$get("post", body = list(hello = "world"))
}, match_requests_on = c("method", "body"))
}

## testing, same body, changed uri in 2nd block
# use_cassette(name = "apple9", {
#   x <- cli$post("post", body = list(hello = "world"))
#   w <- cli$post("get", body = list(hello = "world"))
# }, match_requests_on = c("method", "body"))
# use_cassette(name = "apple9", {
#   NOTHING HERE
# }, match_requests_on = c("method", "body"))
# unlink(file.path(vcr_configuration()$dir, "apple9.yml"))

## End(Not run)

RequestHandlerHttr

Description

Methods for the httr package, building on RequestHandler

Super class

vcr::RequestHandler -> RequestHandlerHttr

Methods

Public methods

Inherited methods

Method new()

Create a new RequestHandlerHttr object

Usage
RequestHandlerHttr$new(request)
Arguments
request

The request from an object of class HttpInteraction

Returns

A new RequestHandlerHttr object


Method clone()

The objects of this class are cloneable with this method.

Usage
RequestHandlerHttr$clone(deep = FALSE)
Arguments
deep

Whether to make a deep clone.

Examples

## Not run: 
vcr_configure(
 dir = tempdir(),
 record = "once"
)

# GET request
library(httr)
load("~/httr_req.rda")
req
x <- RequestHandlerHttr$new(req)
# x$handle()

# POST request
library(httr)
webmockr::httr_mock()
mydir <- file.path(tempdir(), "testing_httr")
invisible(vcr_configure(dir = mydir))
use_cassette(name = "testing2", {
  res <- POST("https://hb.opencpu.org/post", body = list(foo = "bar"))
}, match_requests_on = c("method", "uri", "body"))

load("~/httr_req_post.rda")
insert_cassette("testing3")
httr_req_post
x <- RequestHandlerHttr$new(httr_req_post)
x
# x$handle()
self=x


## End(Not run)

RequestHandlerHttr2

Description

Methods for the httr2 package, building on RequestHandler

Super class

vcr::RequestHandler -> RequestHandlerHttr2

Methods

Public methods

Inherited methods

Method new()

Create a new RequestHandlerHttr2 object

Usage
RequestHandlerHttr2$new(request)
Arguments
request

The request from an object of class HttpInteraction

Returns

A new RequestHandlerHttr2 object


Method clone()

The objects of this class are cloneable with this method.

Usage
RequestHandlerHttr2$clone(deep = FALSE)
Arguments
deep

Whether to make a deep clone.

Examples

## Not run: 
# GET request
library(httr2)
req <- request("https://hb.opencpu.org/post") %>%
   req_body_json(list(foo = "bar"))
x <- RequestHandlerHttr2$new(req)
# x$handle()

# POST request
library(httr2)
mydir <- file.path(tempdir(), "testing_httr2")
invisible(vcr_configure(dir = mydir))
req <- request("https://hb.opencpu.org/post") %>%
  req_body_json(list(foo = "bar"))
use_cassette(name = "testing3", {
  response <- req_perform(req)
}, match_requests_on = c("method", "uri", "body"))
use_cassette(name = "testing3", {
  response2 <- req_perform(req)
}, match_requests_on = c("method", "uri", "body"))

## End(Not run)

Request ignorer

Description

request ignorer methods

Public fields

LOCALHOST_ALIASES

A constant with values: 'localhost', '127.0.0.1', and '0.0.0.0'

ignored_hosts

vector of ignored host URI's

Methods

Public methods


Method new()

Create a new RequestIgnorer object

Usage
RequestIgnorer$new()
Returns

A new RequestIgnorer object


Method ignore_request()

Will ignore any request for which the given function returns TRUE

Usage
RequestIgnorer$ignore_request()
Returns

no return; defines request ignorer hook


Method ignore_localhost()

ignore all localhost values (localhost, 127.0.0.1, 0.0.0.0)

Usage
RequestIgnorer$ignore_localhost()
Returns

no return; sets to ignore all localhost aliases


Method ignore_localhost_value()

ignore a specific named localhost

Usage
RequestIgnorer$ignore_localhost_value(value)
Arguments
value

(character) A localhost value to ignore, e.g., 'localhost'

Returns

no return; defines request ignorer hook


Method ignore_hosts()

ignore any named host

Usage
RequestIgnorer$ignore_hosts(hosts)
Arguments
hosts

(character) vector of hosts to ignore

Returns

no return; adds host to ignore


Method should_be_ignored()

method to determine whether to ignore a request

Usage
RequestIgnorer$should_be_ignored(request)
Arguments
request

request to ignore

Returns

no return; defines request ignorer hook


Method clone()

The objects of this class are cloneable with this method.

Usage
RequestIgnorer$clone(deep = FALSE)
Arguments
deep

Whether to make a deep clone.


RequestMatcherRegistry

Description

handles request matchers

Public fields

registry

initialze registry list with a request, or leave empty

default_matchers

request matchers to use. default: method, uri

Methods

Public methods


Method new()

Create a new RequestMatcherRegistry object

Usage
RequestMatcherRegistry$new(
  registry = list(),
  default_matchers = list("method", "uri")
)
Arguments
registry

initialze registry list with a request, or leave empty

default_matchers

request matchers to use. default: method, uri

Returns

A new RequestMatcherRegistry object


Method register()

Register a custom matcher

Usage
RequestMatcherRegistry$register(name, func)
Arguments
name

matcher name

func

function that describes a matcher, should return a single boolean

Returns

no return; registers the matcher


Method register_built_ins()

Register all built in matchers

Usage
RequestMatcherRegistry$register_built_ins()
Returns

no return; registers all built in matchers


Method try_to_register_body_as_json()

Try to register body as JSON

Usage
RequestMatcherRegistry$try_to_register_body_as_json(r1, r2)
Arguments
r1, r2

Request class objects

Returns

no return; registers the matcher


Method clone()

The objects of this class are cloneable with this method.

Usage
RequestMatcherRegistry$clone(deep = FALSE)
Arguments
deep

Whether to make a deep clone.

Note

r1=from new request; r2=from recorded interaction

Examples

## Not run: 
(x <- RequestMatcherRegistry$new())
x$default_matchers
x$registry

## End(Not run)

Serializer class - base class for JSON/YAML serializers

Description

Serializer class - base class for JSON/YAML serializers

Serializer class - base class for JSON/YAML serializers

Public fields

file_extension

(character) A file extension

path

(character) full path to the yaml file

Methods

Public methods


Method new()

Create a new YAML object

Usage
Serializer$new(file_extension = NULL, path = NULL)
Arguments
file_extension

(character) A file extension

path

(character) path to the cassette, excluding the cassette directory and the file extension

Returns

A new YAML object


Method serialize()

Serializes a hash - REPLACED BY YAML/JSON METHODS

Usage
Serializer$serialize(x, path, bytes)
Arguments
x

(list) the object to serialize

path

(character) the file path

bytes

(logical) whether to preserve exact body bytes or not

Returns

(character) the YAML or JSON string to write to disk


Method deserialize()

Serializes a file - REPLACED BY YAML/JSON METHODS

Usage
Serializer$deserialize()

Method clone()

The objects of this class are cloneable with this method.

Usage
Serializer$clone(deep = FALSE)
Arguments
deep

Whether to make a deep clone.


Cassette serializers

Description

Keeps track of the cassette serializers in a hash-like object

Usage

serializer_fetch(x = "yaml", name)

Details

Private Methods

serialize_get()

Gets a named serializer. This is also run on Serializers$new()

Public fields

serializers

(list) list of serializer names

name

(character) Name of a serializer. "yaml" (default) or "json"

Methods

Public methods


Method new()

Create a new Serializers object

Usage
Serializers$new(serializers = list(), name = "yaml")
Arguments
serializers

(list) list of serializer names

name

(character) Name of a serializer. "yaml" (default) or "json"

Returns

A new Serializers object


Method clone()

The objects of this class are cloneable with this method.

Usage
Serializers$clone(deep = FALSE)
Arguments
deep

Whether to make a deep clone.

Examples

## Not run: 
(aa <- Serializers$new())
aa$name
aa$serializers
yaml_serializer <- aa$serializers$new()
yaml_serializer

x <- Serializers$new(name = "json")
x$serializers$new()
json_serializer <- x$serializers$new()
json_serializer

## End(Not run)

Skip tests if vcr is off

Description

Custom testthat skipper to skip tests if vcr is turned off via the environment variable VCR_TURN_OFF.

Usage

skip_if_vcr_off()

Details

This might be useful if your test will fail with real requests: when the cassette was e.g. edited (a real request produced a 200 status code but you made it a 502 status code for testing the behavior of your code when the API errors) or if the tests are very specific (e.g. testing a date was correctly parsed, but making a real request would produce a different date).

Value

Nothing, skip test.

See Also

turn_off()


split string every N characters

Description

split string every N characters

Usage

str_splitter(str, length)

Arguments

str

(character) a string

length

(integer) number of characters to split by

Examples

## Not run: 
str = "XOVEWVJIEWNIGOIWENVOIWEWVWEW"
str_splitter(str, 5)
str_splitter(str, 5L)

## End(Not run)

UnhandledHTTPRequestError

Description

Handle http request errors

Usage

vcr_last_error()

Details

How this error class is used: If record="once" we trigger this.

Users can use vcr in the context of both use_cassette() and insert_cassette()

For the former, all requests go through the call_block But for the latter, requests go through webmockr.

Where is one place where we can put UnhandledHTTPRequestError that will handle both use_cassette and insert_cassette?

Error situations where this is invoked

Public fields

request

a Request object

cassette

a cassette name

Methods

Public methods


Method new()

Create a new UnhandledHTTPRequestError object

Usage
UnhandledHTTPRequestError$new(request)
Arguments
request

(Request) a Request object

Returns

A new UnhandledHTTPRequestError object


Method run()

Run unhandled request handling

Usage
UnhandledHTTPRequestError$run()
Returns

various


Method construct_message()

Construct and execute stop message for why request failed

Usage
UnhandledHTTPRequestError$construct_message()
Returns

a stop message


Method request_description()

construct request description

Usage
UnhandledHTTPRequestError$request_description()
Returns

character


Method current_matchers()

get current request matchers

Usage
UnhandledHTTPRequestError$current_matchers()
Returns

character


Method match_request_on_headers()

are headers included in current matchers?

Usage
UnhandledHTTPRequestError$match_request_on_headers()
Returns

logical


Method match_request_on_body()

is body includled in current matchers?

Usage
UnhandledHTTPRequestError$match_request_on_body()
Returns

logical


Method formatted_headers()

get request headers

Usage
UnhandledHTTPRequestError$formatted_headers()
Returns

character


Method cassettes_description()

construct description of current or lack thereof cassettes

Usage
UnhandledHTTPRequestError$cassettes_description()
Returns

character


Method cassettes_list()

cassette details

Usage
UnhandledHTTPRequestError$cassettes_list()
Returns

character


Method get_help()

get help message for non-verbose error

Usage
UnhandledHTTPRequestError$get_help()
Returns

character


Method formatted_suggestions()

make suggestions for what to do

Usage
UnhandledHTTPRequestError$formatted_suggestions()
Returns

character


Method format_bullet_point()

add bullet point to beginning of a line

Usage
UnhandledHTTPRequestError$format_bullet_point(lines, index)
Arguments
lines

(character) vector of strings

index

(integer) a number

Returns

character


Method format_foot_note()

make a foot note

Usage
UnhandledHTTPRequestError$format_foot_note(url, index)
Arguments
url

(character) a url

index

(integer) a number

Returns

character


Method suggestion_for()

get a suggestion by key

Usage
UnhandledHTTPRequestError$suggestion_for(key)
Arguments
key

(character) a character string

Returns

character


Method suggestions()

get all suggestions

Usage
UnhandledHTTPRequestError$suggestions()
Returns

list


Method no_cassette_suggestions()

get all no cassette suggestions

Usage
UnhandledHTTPRequestError$no_cassette_suggestions()
Returns

list


Method record_mode_suggestion()

get the appropriate record mode suggestion

Usage
UnhandledHTTPRequestError$record_mode_suggestion()
Returns

character


Method has_used_interaction_matching()

are there any used interactions

Usage
UnhandledHTTPRequestError$has_used_interaction_matching()
Returns

logical


Method match_requests_on_suggestion()

match requests on suggestion

Usage
UnhandledHTTPRequestError$match_requests_on_suggestion()
Returns

list


Method clone()

The objects of this class are cloneable with this method.

Usage
UnhandledHTTPRequestError$clone(deep = FALSE)
Arguments
deep

Whether to make a deep clone.

Examples

## Not run: 
vcr_configure(dir = tempdir())
cassettes()
insert_cassette("turtle")
request <- Request$new("post", 'https://hb.opencpu.org/post?a=5',
  "", list(foo = "bar"))

err <- UnhandledHTTPRequestError$new(request)
err$request_description()
err$current_matchers()
err$match_request_on_headers()
err$match_request_on_body()
err$formatted_headers()
cat(err$formatted_headers(), "\n")
cat(err$cassettes_description(), "\n")
cat(err$cassettes_list(), "\n")
err$formatted_suggestions()
cat(err$format_bullet_point('foo bar', 1), "\n")
err$suggestion_for("use_new_episodes")
err$suggestions()
err$no_cassette_suggestions()
err$record_mode_suggestion()
err$has_used_interaction_matching()
err$match_requests_on_suggestion()

# err$construct_message()

# cleanup
eject_cassette("turtle")
unlink(tempdir())

## End(Not run)
## Not run: 
# vcr_last_error()

## End(Not run)

Use a cassette to record HTTP requests

Description

Use a cassette to record HTTP requests

Usage

use_cassette(
  name,
  ...,
  record = NULL,
  match_requests_on = NULL,
  update_content_length_header = FALSE,
  allow_playback_repeats = FALSE,
  serialize_with = NULL,
  persist_with = NULL,
  preserve_exact_body_bytes = NULL,
  re_record_interval = NULL,
  clean_outdated_http_interactions = NULL
)

Arguments

name

The name of the cassette. vcr will check this to ensure it is a valid file name. Not allowed: spaces, file extensions, control characters (e.g., ⁠\n⁠), illegal characters ('/', '?', '<', '>', '\', ':', '*', '|', and '\"'), dots alone (e.g., '.', '..'), Windows reserved words (e.g., 'com1'), trailing dots (can cause problems on Windows), names longer than 255 characters. See section "Cassette names"

...

a block of code containing one or more requests (required). Use curly braces to encapsulate multi-line code blocks. If you can't pass a code block use insert_cassette() instead.

record

The record mode (default: "once"). See recording for a complete list of the different recording modes.

match_requests_on

List of request matchers to use to determine what recorded HTTP interaction to replay. Defaults to ⁠["method", "uri"]⁠. The built-in matchers are "method", "uri", "host", "path", "headers", "body" and "query"

update_content_length_header

(logical) Whether or not to overwrite the Content-Length header of the responses to match the length of the response body. Default: FALSE

allow_playback_repeats

(logical) Whether or not to allow a single HTTP interaction to be played back multiple times. Default: FALSE.

serialize_with

(character) Which serializer to use. Valid values are "yaml" (default) and "json". Note that you can have multiple cassettes with the same name as long as they use different serializers; so if you only want one cassette for a given cassette name, make sure to not switch serializers, or clean up files you no longer need.

persist_with

(character) Which cassette persister to use. Default: "file_system". You can also register and use a custom persister.

preserve_exact_body_bytes

(logical) Whether or not to base64 encode the bytes of the requests and responses for this cassette when serializing it. See also preserve_exact_body_bytes in vcr_configure(). Default: FALSE

re_record_interval

(integer) How frequently (in seconds) the cassette should be re-recorded. default: NULL (not re-recorded)

clean_outdated_http_interactions

(logical) Should outdated interactions be recorded back to file? default: FALSE

Details

A run down of the family of top level vcr functions

Value

an object of class Cassette

Cassette options

Default values for arguments controlling cassette behavior are inherited from vcr's global configuration. See vcr_configure() for a complete list of options and their default settings. You can override these options for a specific cassette by changing an argument's value to something other than NULL when calling either insert_cassette() or use_cassette().

Behavior

This function handles a few different scenarios:

Cassettes on disk

Note that "eject" only means that the R session cassette is no longer in use. If any interactions were recorded to disk, then there is a file on disk with those interactions.

Using with tests (specifically testthat)

There's a few ways to get correct line numbers for failed tests and one way to not get correct line numbers:

Correct: Either wrap your test_that() block inside your use_cassette() block, OR if you put your use_cassette() block inside your test_that() block put your testthat expectations outside of the use_cassette() block.

Incorrect: By wrapping the use_cassette() block inside your test_that() block with your testthat expectations inside the use_cassette() block, you'll only get the line number that the use_cassette() block starts on.

See Also

insert_cassette(), eject_cassette()

Examples

## Not run: 
library(vcr)
library(crul)
vcr_configure(dir = tempdir())

use_cassette(name = "apple7", {
  cli <- HttpClient$new(url = "https://hb.opencpu.org")
  resp <- cli$get("get")
})
readLines(file.path(tempdir(), "apple7.yml"))

# preserve exact body bytes - records in base64 encoding
use_cassette("things4", {
  cli <- crul::HttpClient$new(url = "https://hb.opencpu.org")
  bbb <- cli$get("get")
}, preserve_exact_body_bytes = TRUE)
## see the body string value in the output here
readLines(file.path(tempdir(), "things4.yml"))

# cleanup
unlink(file.path(tempdir(), c("things4.yml", "apple7.yml")))


# with httr
library(vcr)
library(httr)
vcr_configure(dir = tempdir(), log = TRUE, log_opts = list(file = file.path(tempdir(), "vcr.log")))

use_cassette(name = "stuff350", {
  res <- GET("https://hb.opencpu.org/get")
})
readLines(file.path(tempdir(), "stuff350.yml"))

use_cassette(name = "catfact456", {
  res <- GET("https://catfact.ninja/fact")
})

# record mode: none
library(crul)
vcr_configure(dir = tempdir())

## make a connection first
conn <- crul::HttpClient$new("https://eu.httpbin.org")
## this errors because 'none' disallows any new requests
# use_cassette("none_eg", (res2 <- conn$get("get")), record = "none")
## first use record mode 'once' to record to a cassette
one <- use_cassette("none_eg", (res <- conn$get("get")), record = "once")
one; res
## then use record mode 'none' to see it's behavior
two <- use_cassette("none_eg", (res2 <- conn$get("get")), record = "none")
two; res2

## End(Not run)

Setup vcr for a package

Description

Setup vcr for a package

Usage

use_vcr(dir = ".", verbose = TRUE)

Arguments

dir

(character) path to package root. default's to current directory

verbose

(logical) print progress messages. default: TRUE

Details

Sets a mimimum vcr version, which is usually the latest (stable) version on CRAN. You can of course easily remove or change the version requirement yourself after running this function.

Value

only messages about progress, returns invisible()


Global Configuration Options

Description

Configurable options that define vcr's default behavior.

Usage

vcr_configure(...)

vcr_configure_reset()

vcr_configuration()

vcr_config_defaults()

Arguments

...

configuration settings used to override defaults. See below for a complete list of valid arguments.

Configurable settings

vcr options

File locations
Contexts
Filtering

Errors

Internals
Logging

Cassette Options

These settings can be configured globally, using vcr_configure(), or locally, using either use_cassette() or insert_cassette(). Global settings are applied to all cassettes but are overridden by settings defined locally for individual cassettes.

Examples

vcr_configure(dir = tempdir())
vcr_configure(dir = tempdir(), record = "all")
vcr_configuration()
vcr_config_defaults()
vcr_configure(dir = tempdir(), ignore_hosts = "google.com")
vcr_configure(dir = tempdir(), ignore_localhost = TRUE)


# logging
vcr_configure(dir = tempdir(), log = TRUE,
  log_opts = list(file = file.path(tempdir(), "vcr.log")))
vcr_configure(dir = tempdir(), log = TRUE, log_opts = list(file = "console"))
vcr_configure(dir = tempdir(), log = TRUE,
 log_opts = list(
   file = file.path(tempdir(), "vcr.log"),
   log_prefix = "foobar"
))
vcr_configure(dir = tempdir(), log = FALSE)

# filter sensitive data
vcr_configure(dir = tempdir(),
  filter_sensitive_data = list(foo = "<bar>")
)
vcr_configure(dir = tempdir(),
  filter_sensitive_data = list(foo = "<bar>", hello = "<world>")
)

vcr log file setup

Description

vcr log file setup

Usage

vcr_log_file(file, overwrite = TRUE)

vcr_log_info(message, include_date = TRUE)

Arguments

file

(character) a file path, required

overwrite

(logical) whether or not to overwrite the file at 'file' if it already exists. Default: TRUE

message

(character) a message to log

include_date

(logical) include date and time in each log entry. Default: FALSE

Examples

# user workflow
vcr_configuration()
logfile <- file.path(tempdir(), "vcr.log")
vcr_configure(dir = tempdir(), log = TRUE, log_opts = list(file = logfile))

readLines(logfile) # empty

# log messages
vcr_log_info("hello world!")
readLines(logfile)
vcr_log_info("foo bar")
readLines(logfile)
## many messages
vcr_log_info(c("brown cow", "blue horse"))
readLines(logfile)
vcr_log_info(c("brown cow", "blue horse", "green goat"))
readLines(logfile)

# standalone workflow
# set a file to log to
vcr_log_file((f <- tempfile()))
readLines(f) # empty

# log messages
vcr_log_info("hello world!")
readLines(logfile)
vcr_log_info("foo bar")
readLines(logfile)

# cleanup
unlink(f)
unlink(logfile)

Locate file in tests directory

Description

This function, similar to testthat::test_path(), is designed to work both interactively and during tests, locating files in the ⁠tests/⁠ directory.

Usage

vcr_test_path(...)

Arguments

...

Character vectors giving path component. each character string gets added on to the path, e.g., vcr_test_path("a", "b") becomes tests/a/b relative to the root of the package.

Value

A character vector giving the path

Note

vcr_test_path() assumes you are using testthat for your unit tests.

Examples

if (interactive()) {
vcr_test_path("fixtures")
}

The response of an HTTPInteraction

Description

Custom vcr http response object

Public fields

status

the status of the response

headers

the response headers

body

the response body

http_version

the HTTP version

opts

a list

adapter_metadata

Additional metadata used by a specific VCR adapter

hash

a list

disk

a boolean

Methods

Public methods


Method new()

Create a new VcrResponse object

Usage
VcrResponse$new(
  status,
  headers,
  body,
  http_version,
  opts,
  adapter_metadata = NULL,
  disk
)
Arguments
status

the status of the response

headers

the response headers

body

the response body

http_version

the HTTP version

opts

a list

adapter_metadata

Additional metadata used by a specific VCR adapter

disk

boolean, is body a file on disk

Returns

A new VcrResponse object


Method print()

print method for the VcrResponse class

Usage
VcrResponse$print(x, ...)
Arguments
x

self

...

ignored


Method to_hash()

Create a hash

Usage
VcrResponse$to_hash()
Returns

a list


Method from_hash()

Get a hash back to an R list

Usage
VcrResponse$from_hash(hash)
Arguments
hash

a list

Returns

an VcrResponse object


Method update_content_length_header()

Updates the Content-Length response header so that it is accurate for the response body

Usage
VcrResponse$update_content_length_header()
Returns

no return; modifies the content length header


Method get_header()

Get a header by name

Usage
VcrResponse$get_header(key)
Arguments
key

(character) header name to get

Returns

the header value (if it exists)


Method edit_header()

Edit a header

Usage
VcrResponse$edit_header(key, value = NULL)
Arguments
key

(character) header name to edit

value

(character) new value to assign

Returns

no return; modifies the header in place


Method delete_header()

Delete a header

Usage
VcrResponse$delete_header(key)
Arguments
key

(character) header name to delete

Returns

no return; the header is deleted if it exists


Method content_encoding()

Get the content-encoding header value

Usage
VcrResponse$content_encoding()
Returns

(character) the content-encoding value


Method is_compressed()

Checks if the encoding is one of "gzip" or "deflate"

Usage
VcrResponse$is_compressed()
Returns

logical


Method clone()

The objects of this class are cloneable with this method.

Usage
VcrResponse$clone(deep = FALSE)
Arguments
deep

Whether to make a deep clone.

Examples

## Not run: 
vcr_configure(dir = tempdir())

# basic example of VcrResponse use
url <- "https://google.com"
(cli <- crul::HttpClient$new(url = url))
(res <- cli$get("get", query = list(q = "stuff")))
(x <- VcrResponse$new(res$status_http(), res$response_headers,
   res$parse("UTF-8"), res$response_headers$status))
x$body
x$status
x$headers
x$http_version
x$to_hash()
x$from_hash(x$to_hash())

# update content length header
## example 1
### content-length header present, but no change
url <- "https://fishbase.ropensci.org"
cli <- crul::HttpClient$new(url = url, headers = list(`Accept-Encoding` = '*'))
res <- cli$get("species/34")
x <- VcrResponse$new(res$status_http(), res$response_headers,
   res$parse("UTF-8"), res$response_headers$status)
x$headers$`content-length`
x$update_content_length_header()
x$headers$`content-length`

## example 2
### no content-length header b/c a transfer-encoding header is included
### and no content-length header allowed if transfer-encoding header
### used (via rfc7230)
url <- "https://google.com"
cli <- crul::HttpClient$new(url = url)
res <- cli$get()
x <- VcrResponse$new(res$status_http(), res$response_headers,
   rawToChar(res$content), res$response_headers$status)
x$headers$`content-length` # = NULL
x$update_content_length_header() # no change, b/c header doesn't exist
x$headers$`content-length` # = NULL

## example 3
### content-length header present, and does change
body <- " Hello World "
x <- VcrResponse$new(200, list('content-length'=nchar(body)),
  body, "HTTP/2")
x$headers$`content-length` # = 13
x$body <- gsub("^\\s|\\s$", "", x$body)
x$headers$`content-length` # = 13
x$update_content_length_header()
x$headers$`content-length` # = 11

# check if body is compressed
url <- "https://fishbase.ropensci.org"
(cli <- crul::HttpClient$new(url = url))
(res <- cli$get("species/3"))
res$response_headers
(x <- VcrResponse$new(res$status_http(), res$response_headers,
   res$parse("UTF-8"), res$response_headers$status))
x$content_encoding()
x$is_compressed()

# with disk
url <- "https://google.com"
(cli <- crul::HttpClient$new(url = url))
f <- tempfile()
(res <- cli$get("get", query = list(q = "stuff"), disk = f))
(x <- VcrResponse$new(res$status_http(), res$response_headers,
   f, res$response_headers$status, disk = TRUE))

## End(Not run)

The YAML serializer

Description

class with methods for serializing via the yaml package

Super class

vcr::Serializer -> YAML

Methods

Public methods


Method new()

Create a new YAML object

Usage
YAML$new(path = NULL)
Arguments
path

(character) path to the cassette, excluding the cassette directory and the file extension

Returns

A new YAML object


Method serialize()

Serializes the given hash using internal fxn write_yaml

Usage
YAML$serialize(x, path, bytes)
Arguments
x

(list) the object to serialize

path

(character) the file path

bytes

(logical) whether to preserve exact body bytes or not

Returns

(character) the YAML string to write to disk


Method deserialize()

Deserializes the content at the path using yaml::yaml.load_file

Usage
YAML$deserialize(cassette)
Arguments
cassette

the current cassette object so it's properties can be retrieved

Returns

(list) the deserialized object, an R list


Method clone()

The objects of this class are cloneable with this method.

Usage
YAML$clone(deep = FALSE)
Arguments
deep

Whether to make a deep clone.