gentleman

repository·master·Indexed 22 days ago

https://github.com/h2non/gentleman

A plugin-driven, middleware-oriented toolkit for building highly composable and extensible HTTP clients in Go, built on top of the standard net/http library. It includes packages for request-aware context, middleware management, and a multiplexer (mux) for conditional plugin composition. The toolkit provides various plugins for authentication, body handling, content-type definition, compression, and cookie management.

Tokens
13.3K
Snippets
52
Records
63
Agent score
77%

What's inside gentleman

  1. Overview of gentleman

    master
    gentleman is a full-featured, plugin-driven, and middleware-oriented toolkit for creating rich, versatile, and composable HTTP clients in Go. It is built on top of the standard net/http package and is designed for extensibility through a hierarchical middleware layer and a plugin system. It is particularly well-suited for building domain-specific HTTP API clients.
  2. What is gentleman/context and how is it used?

    master

    The context package provides a request-aware HTTP context designed to share polymorphic data across different plugins within the middleware call chain.

    Key characteristics:

    • Middleware Integration: It is exposed by the middleware layer to allow plugins to communicate.
    • Standard Library Compatibility: It is built on top of the standard Go context package and implements the valid context.Context interface. This means you can use it wherever a standard Go context is expected.
  3. How middleware and plugins work in gentleman

    master

    gentleman uses a hierarchical middleware layer based on plugins to provide custom logic during the HTTP request/response lifecycle. Plugins execute function handlers that can intercept, modify, or stop requests and responses.

    Key behaviors:

    • Execution Order: The middleware stack is executed in FIFO (First-In, First-Out) order.
    • Concurrency: While the stack is designed for a single-thread model, plugins can support goroutines. However, plugin implementors are responsible for preventing data races.
    • Extensibility: The system is designed to allow new phases to be added or custom phases to be triggered.
  4. Understanding gentleman HTTP entities: Client and Request

    master

    Gentleman provides two high-level HTTP entities: Client and Request. Both are middleware-capable, allowing you to plug in custom logic into any of them.

    Entity Roles

    • Client: Designed for reusability. A Client can inherit from another Client and can create multiple Request entities.
    • Request: Designed for specific HTTP request logic that is typically not reused. A Request can inherit from a Client.

    Inheritance and Reusability

    Gentleman uses a hierarchical, inheritance-based middleware layer to achieve strong reusability:

    1. Client Inheritance: A Client can inherit configuration and middleware from another Client.
    2. Request Inheritance: A Request created by a Client implicitly inherits the middleware and configuration of that Client.
    3. Cloning: Both Client and Request entities can be cloned to produce a side-effect-free copy of the entity.
  5. Define HTTP body types with bodytype

    master

    The bodytype plugin allows you to easily define the Content-Type for your HTTP requests. It supports various type aliases that map to specific MIME types. Use bodytype.Type("alias") to set the content type.

    Supported type aliases:

    • html -> text/html
    • json -> application/json
    • xml -> application/xml
    • text -> text/plain
    • urlencoded -> application/x-www-form-urlencoded
    • form -> application/x-www-form-urlencoded
    • form-data -> application/x-www-form-urlencoded
  6. How to create gentleman plugins

    master

    Plugins are sets of middleware function handlers for one or multiple HTTP lifecycle phases. They are consumed by the gentleman middleware layer and can be used for tasks like server discovery, custom HTTP transport, modifying request/response parameters, intercepting traffic, or authentication.

    For implementation details, refer to the plugin package and the provided examples in the repository.

  7. How the gentleman/mux multiplexer works

    master

    The mux package provides an HTTP client multiplexer that allows you to compose plugins based on specific conditions. It supports both request and response phases. You can use matchers to filter which plugins are executed during a request lifecycle.

    Key capabilities include:

    • Custom Matchers: Define arbitrary logic using a function that inspects the *context.Context.
    • Built-in Matchers: Use pre-defined matchers like mux.Method or mux.Host to filter requests.
    • Plugin Composition: Attach plugins directly to a multiplexer instance so they only run when the matchers pass.
    // Example of a multiplexer with a custom matcher
    cli.Use(mux.New().AddMatcher(func (ctx *context.Context) bool {
      return ctx.GetString("$phase") == "request" && ctx.Request.Method == "GET"
    }).Use(url.URL("http://httpbin.org/headers")))
  8. Define URL components with the gentleman/url plugin

    master

    The gentleman/url plugin allows you to build complex URLs by composing different parts of the request. It supports:

    • Base URL: Setting the root domain/host.
    • Path: Defining the path structure.
    • Dynamic Path Params: Using templating (e.g., /:resource) to define placeholders in the path.
    • Param: Providing values to replace the dynamic placeholders.
    // Define the base URL
    cli.Use(url.BaseURL("http://httpbin.org"))
    
    // Define the path with dynamic value
    cli.Use(url.Path("/:resource"))
    
    // Define the path value to be replaced
    cli.Use(url.Param("resource", "get"))
  9. Manage HTTP query parameters with gentleman/query

    master

    The gentleman/query plugin provides middleware to easily manipulate query parameters on your requests. You can use query.Set to add or update parameters and query.Del to remove them. These are applied to the client or specific requests using the .Use() method.

    package main
    
    import (
      "fmt"
      "gopkg.in/h2non/gentleman.v2"
      "gopkg.in/h2non/gentleman.v2/plugins/query"
      "gopkg.in/h2non/gentleman.v2/plugins/url"
    )
    
    func main() {
      // Create a new client
      cli := gentleman.New()
    
      // Define the base URL to use
      cli.Use(url.BaseURL("http://httpbin.org"))
      cli.Use(url.Path("/get"))
    
      // Define a custom query param
      cli.Use(query.Set("foo", "bar"))
    
      // Remove a query param
      cli.Use(query.Del("bar"))
    
      // Perform the request
      res, err := cli.Request().Send()
      if err != nil {
        fmt.Printf("Request error: %s\n", err)
        return
      }
      if !res.Ok {
        fmt.Printf("Invalid server response: %d\n", res.StatusCode)
        return
      }
    
      fmt.Printf("Status: %d\n", res.StatusCode)
      fmt.Printf("Body: %s", res.String())
    }