marco-m / recorder

HTTP traffic record & replay for go

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

recorder

GoDoc CircleCI goreportcard

Overview

The recorder is a small helper package, primarily intended to help with unit tests. It is capable of recording and replaying traffic, avoiding real network requests.

In the default mode, responses are read from disk, allowing the network roundtrip to be avoided. This can be useful for a couple reasons:

  • Faster
  • Works offline
  • Reduces side-effects on called APIs (such as when testing cloud service provider endpoints)

In addition, with the Passthrough mode, requests can be recorded an asserted in unit tests.

Unless the mode is set to Passthrough, the request-response is recorded in a yml on disk, such as:

# request 0
# timestamp 2019-04-30 10:02:04 +0000 UTC
# roundtrip 398ms
request:
  method: POST
  url: https://jsonplaceholder.typicode.com/posts
  headers:
    Content-Type: application/json
response:
  status_code: 201
  headers:
    Cache-Control: no-cache
    Content-Length: '69'
    Content-Type: application/json; charset=utf-8
    Date: Tue, 30 Apr 2019 10:02:04 GMT
    Location: http://jsonplaceholder.typicode.com/posts/101
    Pragma: no-cache
  body: |-
    {
      "title": "hello",
      "body": "world",
      "userId": 1,
      "id": 101
    }

Example usage

// Create a new recorder.
// Data will be saved in testdata/example.yml
rec := recorder.New("testdata/example")

// Create HTTP client with recorder transport
cli := &http.Client{
    Transport: rec,
}

// Perform a request
resp, err := cli.Get("https://jsonplaceholder.typicode.com/posts/1")
if err != nil {
    log.Fatal(err)
}

// Response is only done if required
b, err := httputil.DumpResponse(resp, true)
if err != nil {
    log.Fatal(err)
}
fmt.Println(string(b))

Modes

Modes allow granular control of behavior.

Mode Behavior
Auto Perform network requests if no stored file exists
ReplayOnly Do not allow network traffic, only return stored files
Record Always perform request and overwrite existing files
Passthrough No files are saved on disk but requests can be retrieved with Lookup()

If no mode is set, Auto is used.

The Passthrough mode disabled loading and saving files but can be useful for asserting if the expected requests were made in tests.

Filters

Filters allow removing sensitive data from the saved files.

The filters are executed after the request but before saving files to disk.

Remove header from request

This will remove the Authorization header from the request:

rec := recorder.New("testdata/private-api", recorder.RemoveRequestHeader("Authorization"))

cli := &http.Client{
    Transport: rec,
}

req, _ := http.NewRequest("https://example.com", "application/json", strings.NewReader("{}"))
req.Header.Add("Authorization", "abcdef")

_, err := cli.Do(req)
if err != nil {
    log.Fatal(err)
}

// Authorization header is not saved to disk

Remove header from response

This will remove the Set-Cookie header from the response:

rec := recorder.New("testdata/private-api", recorder.RemoveResponseHeader("Set-Cookie"))

cli := &http.Client{
    Transport: rec,
}

_, err := cli.Get("https://example.com")
if err != nil {
    log.Fatal(err)
}

// The saved file will not contain the Set-Cookie header that was set by the server.

Custom

In addition to the built in filters, custom filters can be implemented by passing functions with a signature func (entry *recorder.Entry) {}.

rec := recorder.New("testdata/request-header", func(e *recorder.Entry) {
    // Modify e.Request and e.Response
})

cli := &http.Client{
    Transport: rec,
}

_, err := cli.Get("https://example.com")
if err != nil {
    log.Fatal(err)
}

Prior art

This library is inspired by:

The reason for writing this library is primarily flexiblity in setting the mode and different API (no VCR references).

License

MIT

About

HTTP traffic record & replay for go

License:MIT License


Languages

Language:Go 100.0%