Record HTTP calls and replay them
R Makefile
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Permalink
Failed to load latest commit information.
R tidy some code and docs, add loggr to remotes Sep 28, 2016
inst
man-roxygen
man
vignettes
.Rbuildignore
.gitignore
.travis.yml
CONDUCT.md
DESCRIPTION
LICENSE
Makefile
NAMESPACE
README.Rmd
README.md
foobar.yml
vcr.Rproj

README.md

vcr

Build Status

An R port of the Ruby gem vcr

Overview/Terminology

  • Cassette: A thing to record HTTP interactions to. Right now the only option is file system, but in the future could be other things, e.g. a key-value store
  • Persisters: defines how to save requests - currently only option is the file system
  • Serializers: defines how to serialize the HTTP response - currently only option is YAML
  • insert cassette: aka, create a cassette
  • eject cassette: aka, check for saved interactions, and replay if found
  • replay: refers to using a cached result of a http request that was recorded earlier
  • How vcr matches: By default it matches on the HTTP method and the URI, but you can tweak this using the match_requests_on option.

Installation

devtools::install_github("ropenscilabs/vcr")
library("vcr")
library("httr")

Best practices

  • vcr for a package test suite
    • put cassettes in a separate folder, and make sure to .Rbuildignore it - depending on its size you may want to add it to .gitignore as well.
    • make sure to add vcr to Suggests in your package
    • If you want to clean up all cassettes at the end of the R session, run xxx
  • vcr as a dependency in a package (i.e., Depends, Imports)
    • probably best to allow the user of your package to determine where cassettes are cached, so exposing vcr configuration tools to users
  • vcr in your R analysis/project
    • still to come ...

Configuration

Without the user doing anything, we set a number of defaults for easy usage:

  • dir = "~/vcr/vcr_cassettes"
  • record = "once"
  • match_requests_on = c("method", "uri")
  • allow_unused_http_interactions = TRUE
  • serialize_with = "yaml"
  • persist_with = "FileSystem"
  • ignore_hosts = NULL
  • ignore_localhost = FALSE
  • ignore_request = NULL
  • uri_parser = httr::parse_url
  • preserve_exact_body_bytes = FALSE
  • preserve_exact_body_bytes_for = FALSE
  • turned_off = FALSE
  • ignore_cassettes = FALSE
  • cassettes = list() # empty set
  • linked_context = NULL
  • vcr_logging = "vcr.log"

You can get the defaults programatically with

vcr_config_defaults()

However, you can change all the above defaults via calling vcr_configure()

vcr_configure(
  dir = "fixtures/vcr_cassettes",
  record = "all"
)
#> <vcr configuration>
#>   Cassette Dir: fixtures/vcr_cassettes
#>   Record: all
#>   URI Parser: httr::parse_url
#>   Match Requests on: method, uri

Calling vcr_configuration() gives you some of the more important defaults in a nice tidy print out

vcr_configuration()
#> <vcr configuration>
#>   Cassette Dir: fixtures/vcr_cassettes
#>   Record: all
#>   URI Parser: httr::parse_url
#>   Match Requests on: method, uri
#> <vcr configuration>
#>   Cassette Dir: ~/vcr/vcr_cassettes
#>   Record: once
#>   URI Parser: httr::parse_url
#>   Match Requests on: method, uri

Basic usage

system.time(
  use_cassette("helloworld", {
    GET("https://httpbin.org/get")
  })
)
#>    user  system elapsed 
#>   0.090   0.014   0.561

The request gets recorded, and all subsequent requests of the same form used the cached HTTP response, and so are much faster

system.time(
  use_cassette("helloworld", {
    GET("https://httpbin.org/get")
  })
)
#>    user  system elapsed 
#>   0.018   0.002   0.066

use_cassette() is an easier approach. An alternative is to use insert_cassett() + eject_cassette().

use_cassette() does both inject and eject operations for you, but you can instead do them manually by using the above functions. You do have to eject the cassette after using inject.

Matchers

vcr looks for similarity in your HTTP requests to cached requests. You can set what is examined about the request with one or more of the following options:

  • body
  • headers
  • host
  • method
  • path
  • query
  • uri

By default, we use method (HTTP method, e.g., GET) and uri (test for exact match against URI).

You can set your own options like:

use_cassette(name = "one", {
    POST("https://httpbin.org/post", add_headers(a = 5))
  }, 
  match_requests_on = c('method', 'headers', 'query')
)
#> Response [https://httpbin.org/post]
#>   Date: 2016-09-28 19:07
#>   Status: 200
#>   Content-Type: application/json
#>   Size: 406 B
#> {
#>   "args": {}, 
#>   "data": "", 
#>   "files": {}, 
#>   "form": {}, 
#>   "headers": {
#>     "A": "5", 
#>     "Accept": "application/json, text/xml, application/xml, */*", 
#>     "Accept-Encoding": "gzip, deflate", 
#>     "Content-Length": "0", 
#> ...

vcr in other languages

The canonical vcr (in Ruby) lists ports in other languages at https://github.com/vcr/vcr

Meta

  • Please report any issues or bugs
  • License: MIT
  • Get citation information for vcr in R doing citation(package = 'vcr')
  • Please note that this project is released with a Contributor Code of Conduct. By participating in this project you agree to abide by its terms.

ropensci_footer