# Configure vcr

#### Scott Chamberlain

#### 2023-06-24

# vcr configuration

`vcr` configuration

    library("vcr")

    library("vcr")

You can also get the default configuration variables via `vcr_config_defaults()`

    vcr_config_defaults()
    #> $warn_on_empty_cassette
    #> [1] TRUE
    #>
    #> $quiet
    #> [1] TRUE
    #>
    #> $verbose_errors
    #> [1] FALSE
    #>
    #> $write_disk_path
    #> NULL
    #>
    #> $filter_query_parameters
    #> NULL
    #>
    #> $filter_response_headers
    #> NULL
    #>
    #> $filter_request_headers
    #> NULL
    #>
    #> $filter_sensitive_data_regex
    #> NULL
    #>
    #> $filter_sensitive_data
    #> NULL
    #>
    #> $log_opts
    #> $log_opts$file
    #> [1] "vcr.log"
    #>
    #> $log_opts$log_prefix
    #> [1] "Cassette"
    #>
    #> $log_opts$date
    #> [1] TRUE
    #>
    #>
    #> $log
    #> [1] FALSE
    #>
    #> $linked_context
    #> NULL
    #>
    #> $cassettes
    #> list()
    #>
    #> $allow_http_connections_when_no_cassette
    #> [1] FALSE
    #>
    #> $clean_outdated_http_interactions
    #> [1] FALSE
    #>
    #> $re_record_interval
    #> NULL
    #>
    #> $turned_off
    #> [1] FALSE
    #>
    #> $preserve_exact_body_bytes
    #> [1] FALSE
    #>
    #> $uri_parser
    #> [1] "crul::url_parse"
    #>
    #> $ignore_request
    #> NULL
    #>
    #> $ignore_localhost
    #> [1] FALSE
    #>
    #> $ignore_hosts
    #> NULL
    #>
    #> $persist_with
    #> [1] "FileSystem"
    #>
    #> $json_pretty
    #> [1] FALSE
    #>
    #> $serialize_with
    #> [1] "yaml"
    #>
    #> $allow_unused_http_interactions
    #> [1] TRUE
    #>
    #> $match_requests_on
    #> [1] "method" "uri"
    #>
    #> $record
    #> [1] "once"
    #>
    #> $dir
    #> [1] "."

These defaults are set when you load `vcr` - you can override any of them as described below.

## Set configuration variables

Use `vcr_configure()` to set configuration variables.

For example, set a single variable:

    vcr_configure(
      dir = "foobar/vcr_cassettes"
    )
    #> <vcr configuration>
    #>   Cassette Dir: foobar/vcr_cassettes
    #>   Record: once
    #>   Serialize with: yaml
    #>   URI Parser: crul::url_parse
    #>   Match Requests on: method, uri
    #>   Preserve Bytes?: FALSE
    #>   Logging?: FALSE
    #>   ignored hosts:
    #>   ignore localhost?: FALSE
    #>   Write disk path:

Or many at once:

    vcr_configure(
      dir = "foobar/vcr_cassettes",
      record = "all"
    )
    #> <vcr configuration>
    #>   Cassette Dir: foobar/vcr_cassettes
    #>   Record: all
    #>   Serialize with: yaml
    #>   URI Parser: crul::url_parse
    #>   Match Requests on: method, uri
    #>   Preserve Bytes?: FALSE
    #>   Logging?: FALSE
    #>   ignored hosts:
    #>   ignore localhost?: FALSE
    #>   Write disk path:

## Re-set to defaults

    vcr_configure_reset()

## Details on some of the config options

### dir

Directory where cassettes are stored

    vcr_configure(dir = "new/path")
    #> <vcr configuration>
    #>   Cassette Dir: new/path
    #>   Record: once
    #>   Serialize with: yaml
    #>   URI Parser: crul::url_parse
    #>   Match Requests on: method, uri
    #>   Preserve Bytes?: FALSE
    #>   Logging?: FALSE
    #>   ignored hosts:
    #>   ignore localhost?: FALSE
    #>   Write disk path:

### record

The record mode

One of: ‘all’, ‘none’, ‘new_episodes’, ‘once’. See `?recording` for info on the options

    vcr_configure(record = "new_episodes")
    #> <vcr configuration>
    #>   Cassette Dir: new/path
    #>   Record: new_episodes
    #>   Serialize with: yaml
    #>   URI Parser: crul::url_parse
    #>   Match Requests on: method, uri
    #>   Preserve Bytes?: FALSE
    #>   Logging?: FALSE
    #>   ignored hosts:
    #>   ignore localhost?: FALSE
    #>   Write disk path:

### match_requests_on

Customize how `vcr` matches requests

    vcr_configure(match_requests_on = c('query', 'headers'))
    #> <vcr configuration>
    #>   Cassette Dir: new/path
    #>   Record: new_episodes
    #>   Serialize with: yaml
    #>   URI Parser: crul::url_parse
    #>   Match Requests on: query, headers
    #>   Preserve Bytes?: FALSE
    #>   Logging?: FALSE
    #>   ignored hosts:
    #>   ignore localhost?: FALSE
    #>   Write disk path:

### allow_unused_http_interactions

Allow HTTP connections when no cassette

Default is `TRUE`, and thus does not error when http interactions are unused. You can set to `FALSE` in which case vcr errors when a cassette is ejected and not all http interactions have been used.

    vcr_configure(allow_unused_http_interactions = FALSE)
    #> <vcr configuration>
    #>   Cassette Dir: new/path
    #>   Record: new_episodes
    #>   Serialize with: yaml
    #>   URI Parser: crul::url_parse
    #>   Match Requests on: query, headers
    #>   Preserve Bytes?: FALSE
    #>   Logging?: FALSE
    #>   ignored hosts:
    #>   ignore localhost?: FALSE
    #>   Write disk path:

### serialize_with

Which serializer to use: “yaml” or “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.

    vcr_configure(serialize_with = "yaml")
    #> <vcr configuration>
    #>   Cassette Dir: new/path
    #>   Record: new_episodes
    #>   Serialize with: yaml
    #>   URI Parser: crul::url_parse
    #>   Match Requests on: query, headers
    #>   Preserve Bytes?: FALSE
    #>   Logging?: FALSE
    #>   ignored hosts:
    #>   ignore localhost?: FALSE
    #>   Write disk path:

### persist_with

Which persister to use. Right now only option is “FileSystem”

    vcr_configure(persist_with = "FileSystem")
    #> <vcr configuration>
    #>   Cassette Dir: new/path
    #>   Record: new_episodes
    #>   Serialize with: yaml
    #>   URI Parser: crul::url_parse
    #>   Match Requests on: query, headers
    #>   Preserve Bytes?: FALSE
    #>   Logging?: FALSE
    #>   ignored hosts:
    #>   ignore localhost?: FALSE
    #>   Write disk path:

### ignoring some requests

ignore_hosts

Specify particular hosts to ignore. By ignore, we mean that real HTTP requests to the ignored host will be allowed to occur, while all others will not.

    vcr_configure(ignore_hosts = "google.com")
    #> <vcr configuration>
    #>   Cassette Dir: new/path
    #>   Record: new_episodes
    #>   Serialize with: yaml
    #>   URI Parser: crul::url_parse
    #>   Match Requests on: query, headers
    #>   Preserve Bytes?: FALSE
    #>   Logging?: FALSE
    #>   ignored hosts: google.com
    #>   ignore localhost?: FALSE
    #>   Write disk path:

ignore_localhost

Ignore all localhost requests

    vcr_configure(ignore_localhost = TRUE)
    #> <vcr configuration>
    #>   Cassette Dir: new/path
    #>   Record: new_episodes
    #>   Serialize with: yaml
    #>   URI Parser: crul::url_parse
    #>   Match Requests on: query, headers
    #>   Preserve Bytes?: FALSE
    #>   Logging?: FALSE
    #>   ignored hosts: google.com
    #>   ignore localhost?: TRUE
    #>   Write disk path:

ignore_request

THIS DOESN’T WORK YET

How to ignore requests

For ignoring requests, you can for example, have real http requests go through (ignored by `vcr`) while other requests are handled by `vcr`. For example, let’s say you want requests to `google.com` to be ignored:

    vcr_configure(ignore_hosts = "google.com")
    use_cassette("foo_bar", {
      crul::HttpClient$new("https://httpbin.org/get")$get()
      crul::HttpClient$new("https://google.com")$get()
    })

The request to httpbin.org will be handled by `vcr`, a cassette created for the request/response to that url, while the google.com request will be ignored and not cached at all.

Note: ignoring requests only works for the `crul` package for now; it should work for `httr` in a later `vcr` version.

### uri_parse

Which uri parser to use

By default we use `crul::url_parse`, but you can use a different one. Remember to pass in the function quoted, and namespaced.

    vcr_configure(uri_parser = "urltools::url_parse")
    #> <vcr configuration>
    #>   Cassette Dir: new/path
    #>   Record: new_episodes
    #>   Serialize with: yaml
    #>   URI Parser: urltools::url_parse
    #>   Match Requests on: query, headers
    #>   Preserve Bytes?: FALSE
    #>   Logging?: FALSE
    #>   ignored hosts: google.com
    #>   ignore localhost?: TRUE
    #>   Write disk path:

### preserve_exact_body_bytes

Some HTTP servers are not well-behaved and respond with invalid data. Set `preserve_exact_body_bytes` to `TRUE` to base64 encode the result body in order to preserve the bytes exactly as-is. `vcr` does not do this by default, since base64-encoding the string removes the human readability of the cassette.

    vcr_configure(preserve_exact_body_bytes = TRUE)
    #> <vcr configuration>
    #>   Cassette Dir: new/path
    #>   Record: new_episodes
    #>   Serialize with: yaml
    #>   URI Parser: urltools::url_parse
    #>   Match Requests on: query, headers
    #>   Preserve Bytes?: TRUE
    #>   Logging?: FALSE
    #>   ignored hosts: google.com
    #>   ignore localhost?: TRUE
    #>   Write disk path:

### filter_sensitive_data

A named list of values to replace. Sometimes your package or script is working with sensitive tokens/keys, which you do not want to accidentally share with the world.

Before recording (writing to a cassette) we do the replacement and then when reading from the cassette we do the reverse replacement to get back to the real data.

    vcr_configure(
      filter_sensitive_data = list("<some_api_key>" = Sys.getenv('MY_API_KEY'))
    )

Before recording to disk, the env var `MY_API_KEY` is retrieved from your machine, and we find instances of it, and replace with `<some_api_key>`. When replaying to create the HTTP response object we put the real value of the env var back in place.

To target specific request or response headers see `filter_request_headers` and `filter_response_headers`.

### filter_request_headers

Expects a character vector or a named list. If a character vector, or any unnamed element in a list, the request header is removed before being written to the cassette.

If a named list is passed, the name is the header and the value is the value with which to replace the real value.

A request header you set to remove or replace is only removed/replaced from the cassette, and any requests using a cassette, but will still be in your crul or httr response objects on a real request that creates the cassette.

Examples:

    vcr_configure(
      filter_request_headers = "Authorization"
    )
    vcr_configure(
      filter_request_headers = c("Authorization", "User-Agent")
    )
    vcr_configure(
      filter_request_headers = list(Authorization = "<<<not-my-bearer-token>>>")
    )

### filter_response_headers

Expects a character vector or a named list. If a character vector, or any unnamed element in a list, the response header is removed before being written to the cassette.

If a named list is passed, the name is the header and the value is the value with which to replace the real value.

A response header you set to remove or replace is only removed/replaced from the cassette, and any requests using a cassette, but will still be in your crul or httr response objects on a real request that creates the cassette.

Examples:

    vcr_configure(
      filter_response_headers = "server"
    )
    vcr_configure(
      filter_response_headers = c("server", "date")
    )
    vcr_configure(
      filter_response_headers = list(server = "fake-server")
    )

### filter_query_parameters

Expects a character vector or a named list. If a character vector, or any unnamed element in a list, the query parameter is removed (both parameter name and value) before being written to the cassette.

If a named list is passed, the name is the query parameter name and the value is the value with which to replace the real value.

A response header you set to remove or replace is only removed/replaced from the cassette, and any requests using a cassette, but will still be in your crul or httr response objects on a real request that creates the cassette.

Beware of your `match_requests_on` option when using this filter. If you filter out a query parameter it’s probably a bad idea to match on `query` given that there is no way for vcr to restore the exact http request from your cassette after one or more query parameters is removed or changed. One way you could filter a query parameter and still match on query or at least on the complete uri is to use replacement behavior (a named list), but instead of `list(a="b")` use two values `list(a=c("b","c"))`, where “c” is the string to be stored in the cassette. You could of course replace those values with values from environment variables so that you obscure the real values if your code is public.

Examples:

    # completely drop parameter "user"
    vcr_configure(
      filter_query_parameters = "user"
    )
    # completely drop parameters "user" and "api_key"
    vcr_configure(
      filter_query_parameters = c("user", "api_key")
    )
    # replace the value of parameter "api_key" with "fake-api-key"
    # NOTE: in this case there's no way to put back any value on
    # subsequent requests, so we have to match by dropping this
    # parameter value before comparing URIs
    vcr_configure(
      filter_query_parameters = list(api_key = "fake-api-key")
    )
    # replace the value found at Sys.getenv("MY_API_KEY") of parameter
    # "api_key" with the value "foo". When using a cassette on subsequent
    # requests, we can replace "foo" with the value at Sys.getenv("MY_API_KEY")
    # before doing the URI comparison
    vcr_configure(
      filter_query_parameters = list(api_key = c(Sys.getenv("MY_API_KEY"), "foo"))
    )

## More documentation

Check out the http testing book for a lot more documentation on `vcr`, `webmockr`, and `crul`