requests Go Library

repository·main·Indexed 23 days ago

https://github.com/earthboundkid/requests

A fluent HTTP client library for Go designed to reduce the verbosity of the standard net/http package. It features a declarative Builder API for constructing requests, automatic resource management, built-in response validation, and helpers for JSON handling, URL manipulation, and recording/replaying responses for testing via the reqtest package.

Tokens
8.2K
Snippets
17
Records
75
Agent score
80%

What's inside requests

  1. How the requests.Builder works

    main

    The core of the library is the requests.Builder type, which provides a fluent API for building and sending HTTP requests. Instead of the verbose boilerplate required by net/http, you use method chaining to declaratively describe your request.

    Key characteristics:

    • Fluent API: Methods return a pointer to the same builder, allowing chaining.
    • Automatic Resource Management: It automatically handles closing the response body.
    • Default Validation: It checks that response status codes are in the 2XX range by default.
    • Context Required: Every request must be executed using .Fetch(ctx), where ctx is a context.Context.
    err := requests.
    	URL("http://example.com").
    	ToString(&s).
    	Fetch(ctx)
  2. Use BodyGetter to provide request bodies

    main

    A BodyGetter is a function type used by request builders to provide a source for the request body. It returns an io.ReadCloser and an error. This abstraction allows the request to lazily open and read the body content only when the request is actually executed.

    Common ways to create a BodyGetter include using raw bytes, files, JSON, or form data.

  3. Use optional query parameters with ParamOptional

    main

    The ParamOptional method allows you to define query parameters that should only be included in the final URL if they are not already present. This is useful for setting default values or avoiding overwriting existing parameters when building URLs from a base.

    • If the key is already present in the query string, ParamOptional does nothing.
    • If the key is not present and the provided values are not empty, the parameter is added.
    • If the key is not present but the provided values are empty, nothing is added.
  4. Use the Builder for HTTP requests

    main

    The Builder struct provides a fluent, declarative API for building URLs, creating http.Request objects, or executing full HTTP requests with built-in validation and response handling. It supports method chaining to configure various aspects of a request.

    Core Capabilities

    • Build a url.URL: Use Builder.URL() after configuring the scheme, host, path, and parameters.
    • Build an http.Request: Use Builder.Request(ctx) after configuring the method, headers, and body.
    • Execute a request: Use Builder.Do(req) to send an existing request with validation/handling, or Builder.Fetch(ctx) to build, send, and handle a request in one step.

    Configuration Patterns

    • Base Configuration: You can create a base Builder for a specific API and use Builder.Clone() to create new builders for specific endpoints without mutating the original.
    • Validation: Use AddValidator(h ResponseHandler) to add custom validation logic. If no validators are added, DefaultValidator is used. Adding a validator disables the default one.
    • Response Handling: Use Handle(h ResponseHandler) to define how the response should be processed (e.g., parsing JSON or converting to a string).
  5. Use Config to extend the Builder

    main
    The Config type is a functional option pattern used to extend a Builder by setting multiple options at once. You can pass one or more Config functions to a builder to configure complex behaviors like compression, multipart bodies, or testing environments.
  6. POST a raw byte body

    main

    To send a POST request with a raw byte slice as the body, use .BodyBytes([]byte) and set the content type using .ContentType("type").

    err := requests.
    	URL("https://postman-echo.com/post").
    	BodyBytes([]byte(`hello, world`)).
    	ContentType("text/plain").
    	Fetch(ctx)
  7. Manipulate URLs and query parameters

    main

    The builder allows you to modify parts of the URL before the request is sent. You can change the host with .Hostf(format, ...) and add query parameters using .Param(key, value) or .ParamInt(key, int). Call .URL() to retrieve the constructed *url.URL object.

    u, err := requests.
    	URL("https://prod.example.com/get?a=1&b=2").
    	Hostf("%s.example.com", "dev1").
    	Param("b", "3").
    	ParamInt("c", 4).
    	URL()
    if err != nil { /* ... */ }
    fmt.Println(u.String()) // https://dev1.example.com/get?a=1&b=3&c=4
  8. Set custom headers for a request

    main

    Use .Header(key, value) for arbitrary headers, or convenience methods like .UserAgent(string) and .ContentType(string).

    // Set headers
    var headers postman
    err := requests.
    	URL("https://postman-echo.com/get").
    	UserAgent("bond/james-bond").
    	ContentType("secret").
    	Header("martini", "shaken").
    	Fetch(ctx)
  9. Record and replay responses for testing

    main

    Use the reqtest package (part of the requests ecosystem) to record real HTTP interactions to the file system and replay them in subsequent test runs. This is useful for creating deterministic tests without hitting live endpoints.

    1. Record: Use reqtest.Record(nil, "directory") in the .Transport() method.
    2. Replay: Use reqtest.Replay("directory") in the .Transport() method.
    // record a request to the file system
    var s1, s2 string
    err := requests.URL("http://example.com").
    	Transport(reqtest.Record(nil, "somedir")).
    	ToString(&s1).
    	Fetch(ctx)
    check(err)
    
    // now replay the request in tests
    err = requests.URL("http://example.com").
    	Transport(reqtest.Replay("somedir")).
    	ToString(&s2).
    	Fetch(ctx)
    check(err)
    assert(s1 == s2) // true
  10. Perform a simple GET request into a string

    main

    To fetch the body of a GET request and store it in a string variable, use the .ToString(&variable) method before calling .Fetch(ctx).

    var s string
    err := requests.
    	URL("http://example.com").
    	ToString(&s).
    	Fetch(ctx)
  11. POST a JSON object and parse the response JSON

    main

    You can chain .BodyJSON(&requestStruct) to send a JSON payload and .ToJSON(&responseStruct) to parse the resulting response in a single chain.

    var res placeholder
    req := placeholder{
    	Title:  "foo",
    	Body:   "baz",
    	UserID: 1,
    }
    err := requests.
    	URL("/posts").
    	Host("jsonplaceholder.typicode.com").
    	BodyJSON(&req).
    	ToJSON(&res).
    	Fetch(ctx)