liveBook · Manning

Http.RoundTripper

As explained in Go by Example

http.RoundTripper is a Go interface whose RoundTrip method executes a single HTTP transaction and returns the response or an error.

http.RoundTripper is the extension point behind http.Client's Transport field. Its RoundTrip method accepts an HTTP request and returns an HTTP response or an error, letting a client delegate request and response handling to a replaceable implementation. A transport may establish TCP connections, send requests, process responses, and reuse pooled connections. section 7.4.1 section 7.5.1

Use a shared http.Transport when making requests so its connection pool can be reused. http.DefaultTransport is the package default, and http.DefaultClient uses it. Client also exposes CheckRedirect and Timeout for redirect handling and the maximum duration of a round trip. section 7.4.1

A custom transport can be a small function adapter rather than a struct. Define a function type with the same request-and-response signature, give that type a RoundTrip method that calls the function, and Go implicitly recognizes it as a RoundTripper. Assign the resulting value to Client.Transport. section 7.5.1

Fake a response in a unit test

A fake RoundTripper can return a chosen *http.Response directly, allowing code that calls Send through an http.Client to be tested without starting an HTTP server. For example, return StatusInternalServerError and assert that Send records and returns that status. This gives precise control over responses while keeping the test fast. section 7.5.2 section 7.6

A fake transport complements rather than replaces network-level tests. Use it to isolate request-handling behavior; use an httptest server when the client must be exercised across TCP and HTTP layers. Wrapper transports are also useful: a LogRoundTripper can log request URLs, then delegate handling to another RoundTripper such as http.DefaultTransport. section 7.6 section 7.7

Listing 7.7 Testing with a fake RoundTripper (hit/hit_test.go)
package hit

import (
    "net/http"
    "testing"
)
. . .
func TestSendStatusCode(t *testing.T) {
    t.Parallel()

    req, err := http.NewRequest(http.MethodGet, "/", http.NoBody)
    if err != nil {
        t.Fatalf("creating http request: %v", err)
    }

    fake := func(_ *http.Request) (*http.Response, error) {
        return &http.Response{
            StatusCode: http.StatusInternalServerError,
        }, nil
    }
    client := &http.Client{
        Transport: roundTripperFunc(fake),
    }

    result := Send(client, req)

    if result.Status != http.StatusInternalServerError {
        t.Errorf(
            "got %d, want %d",
             result.Status, http.StatusInternalServerError,
        )
    }
}

This test demonstrates the full substitution path: a closure becomes a transport, the transport is assigned to Client.Transport, and Send receives the fake status response. section 7.5.2

How Go by Example covers it

How deep it goes
Defines the interface, explains function-type satisfaction, and demonstrates a fake-response test; defers real network testing to httptest.
Examples
Uses a roundTripperFunc adapter, a fake internal-server-error response, Send status assertions, and a proposed logging wrapper.
What it assumes
Assumes familiarity with HTTP requests, responses, and Go methods while illustrating implicit interface satisfaction with a function type.
What you can do after
Apply it via http.Client.Transport to fake controlled responses in unit tests or wrap delegated request handling.
How it connects
Connects http.Client, http.Transport, connection pooling, implicit interface satisfaction, test doubles, and httptest.

Related concepts

This explainer was generated by Manning's knowledge graph from the text of Go by Example. The section links point to the parts of the book it draws on.