Convert Figma logo to code with AI

h2non logogentleman

Plugin-driven, extensible HTTP client toolkit for Go

1,075
53
1,075
25

Top Related Projects

9,906

Simple HTTP and REST client library for Go

GoRequest -- Simplified HTTP client ( inspired by nodejs SuperAgent )

4,217

Simple Go HTTP client with Black Magic

1,672

A Go HTTP client library for creating and sending API requests

A Go "clone" of the great and famous Requests library

21,607

Fast HTTP package for Go. Tuned for high performance. Zero memory allocations in hot paths. Up to 10x faster than net/http

Quick Overview

Gentleman is a full-featured, plugin-driven HTTP client toolkit for Go. It provides a simple and expressive way to create and send HTTP requests, with support for middleware, interceptors, and powerful composition capabilities.

Pros

  • Highly extensible and customizable through plugins and middleware
  • Supports both synchronous and asynchronous request handling
  • Provides a fluent and expressive API for building and sending requests
  • Offers built-in support for common features like retries, timeouts, and request/response debugging

Cons

  • Learning curve may be steeper compared to simpler HTTP clients
  • Might be overkill for basic HTTP requests
  • Documentation could be more comprehensive, especially for advanced features

Code Examples

  1. Simple GET request:
resp, err := gentleman.New().
    URL("https://api.example.com").
    Path("/users").
    AddQuery("limit", "10").
    Send()

if err != nil {
    fmt.Printf("Request error: %s\n", err)
    return
}

fmt.Printf("Status: %d\n", resp.StatusCode)
fmt.Printf("Body: %s\n", resp.String())
  1. POST request with JSON payload:
client := gentleman.New()
resp, err := client.
    Post().
    URL("https://api.example.com/users").
    JSON(map[string]string{"name": "John", "email": "john@example.com"}).
    Send()

if err != nil {
    fmt.Printf("Request error: %s\n", err)
    return
}

fmt.Printf("Status: %d\n", resp.StatusCode)
  1. Using middleware for authentication:
client := gentleman.New()
client.Use(func(ctx *gentleman.Context, h gentleman.Handler) {
    ctx.Request.SetHeader("Authorization", "Bearer token123")
    h.Next(ctx)
})

resp, err := client.
    URL("https://api.example.com/protected").
    Get().
    Send()

if err != nil {
    fmt.Printf("Request error: %s\n", err)
    return
}

fmt.Printf("Status: %d\n", resp.StatusCode)

Getting Started

To use Gentleman in your Go project, first install it:

go get -u gopkg.in/h2non/gentleman.v2

Then, import and use it in your code:

import (
    "fmt"
    "gopkg.in/h2non/gentleman.v2"
)

func main() {
    client := gentleman.New()
    resp, err := client.
        URL("https://api.example.com").
        Path("/hello").
        Get().
        Send()

    if err != nil {
        fmt.Printf("Request error: %s\n", err)
        return
    }

    fmt.Printf("Response: %s\n", resp.String())
}

This example creates a new client, sets the URL and path, performs a GET request, and prints the response.

Competitor Comparisons

9,906

Simple HTTP and REST client library for Go

Pros of Resty

  • More feature-rich with built-in support for various authentication methods, retries, and timeouts
  • Simpler API with a fluent interface, making it easier to use for beginners
  • Active development with frequent updates and a larger community

Cons of Resty

  • Less flexible and customizable compared to Gentleman's plugin-based architecture
  • Heavier dependency with more code, which may increase binary size
  • May be overkill for simple use cases or when fine-grained control is needed

Code Comparison

Resty:

resp, err := resty.New().R().
    SetHeader("Content-Type", "application/json").
    SetBody(data).
    Post("https://api.example.com/users")

Gentleman:

resp, err := gentleman.New().
    URL("https://api.example.com").
    Path("/users").
    Method("POST").
    Type("json").
    JSON(data).
    Send()

Both libraries offer concise ways to make HTTP requests, but Resty's API is slightly more compact and intuitive for simple cases. Gentleman's approach provides more explicit control over request components, which can be beneficial for complex scenarios or when building reusable client libraries.

GoRequest -- Simplified HTTP client ( inspired by nodejs SuperAgent )

Pros of gorequest

  • Simpler API with a more fluent interface
  • Built-in support for multipart file uploads
  • Easier to set and use cookies

Cons of gorequest

  • Less actively maintained (last commit over 3 years ago)
  • Fewer middleware options and extensibility features
  • Limited support for advanced HTTP/2 features

Code Comparison

gorequest:

resp, body, errs := gorequest.New().
    Get("http://example.com").
    Set("Content-Type", "application/json").
    End()

gentleman:

resp, err := gentleman.New().
    URL("http://example.com").
    Method("GET").
    SetHeader("Content-Type", "application/json").
    Send()

Both libraries provide a fluent interface for making HTTP requests, but gentleman offers a more modular and extensible approach. gorequest has a simpler API that may be easier for beginners, while gentleman provides more advanced features and better support for middleware.

gentleman is more actively maintained and offers better performance, especially for concurrent requests. However, gorequest's simpler API and built-in support for certain features like file uploads may be preferable for simpler use cases.

Choose gorequest for quick, simple HTTP requests with an easy-to-use API. Opt for gentleman if you need a more robust, extensible, and actively maintained library with better performance for complex scenarios.

4,217

Simple Go HTTP client with Black Magic

Pros of req

  • Simpler API with a more intuitive design for common HTTP operations
  • Built-in support for HTTP/2 and HTTP/3
  • Better performance due to optimized implementation and connection reuse

Cons of req

  • Less extensive middleware ecosystem compared to gentleman
  • Fewer advanced features for complex request customization
  • Limited support for older Go versions (requires Go 1.16+)

Code Comparison

req:

client := req.C().EnableDebugLog()
resp, err := client.R().
    SetHeader("Accept", "application/json").
    SetQueryParam("page", "1").
    Get("https://api.example.com/users")

gentleman:

client := gentleman.New()
resp, err := client.
    URL("https://api.example.com/users").
    AddHeader("Accept", "application/json").
    AddQuery("page", "1").
    Get()

Both libraries offer concise ways to make HTTP requests, but req's API is slightly more streamlined. gentleman provides a more chainable approach, while req focuses on a simpler method-based structure. req's client creation is more straightforward, whereas gentleman offers more granular control over the client configuration.

1,672

A Go HTTP client library for creating and sending API requests

Pros of Sling

  • Lightweight and focused on simplicity
  • Built-in OAuth1a and OAuth2 support
  • Supports both JSON and form-encoded requests

Cons of Sling

  • Less feature-rich compared to Gentleman
  • Limited middleware and plugin ecosystem
  • Fewer customization options for request/response handling

Code Comparison

Sling:

client := &http.Client{}
req, _ := http.NewRequest("GET", "https://api.example.com", nil)
sling := sling.New().Client(client).Base("https://api.example.com/")
resp, _ := sling.Do(req)

Gentleman:

cli := gentleman.New()
cli.URL("https://api.example.com")
req := cli.Request()
req.Method("GET")
resp, _ := req.Send()

Both libraries provide a clean and intuitive API for making HTTP requests, but Gentleman offers a more extensive set of features and middleware options. Sling focuses on simplicity and ease of use, while Gentleman provides greater flexibility and customization.

Sling is a good choice for projects that require straightforward HTTP requests with built-in OAuth support. Gentleman is better suited for more complex scenarios that demand advanced request/response manipulation and a rich middleware ecosystem.

A Go "clone" of the great and famous Requests library

Pros of grequests

  • Simpler API, more closely resembling Python's requests library
  • Built-in support for concurrent requests using gevent
  • Easier to use for developers familiar with Python's requests library

Cons of grequests

  • Less flexible and customizable compared to gentleman
  • Limited middleware support
  • Fewer built-in features for advanced HTTP client operations

Code Comparison

grequests:

import "github.com/levigross/grequests"

resp, err := grequests.Get("http://api.example.com", nil)
if err != nil {
    log.Fatalln("Unable to make request: ", err)
}

gentleman:

import "gopkg.in/h2non/gentleman.v2"

cli := gentleman.New()
resp, err := cli.Request().URL("http://api.example.com").Send()
if err != nil {
    log.Fatalln("Request error: ", err)
}

Both libraries provide easy-to-use HTTP client functionality in Go, but gentleman offers more advanced features and customization options, while grequests focuses on simplicity and familiarity for Python developers transitioning to Go. gentleman's plugin system and middleware support make it more suitable for complex HTTP client scenarios, whereas grequests excels in straightforward use cases and concurrent requests.

21,607

Fast HTTP package for Go. Tuned for high performance. Zero memory allocations in hot paths. Up to 10x faster than net/http

Pros of fasthttp

  • Significantly faster performance and lower memory usage
  • Optimized for high-concurrency scenarios
  • Provides both client and server implementations

Cons of fasthttp

  • Less feature-rich compared to the standard net/http package
  • May require more manual handling of certain HTTP operations
  • Not fully compatible with net/http interfaces

Code Comparison

fasthttp client example:

client := &fasthttp.Client{}
req := fasthttp.AcquireRequest()
resp := fasthttp.AcquireResponse()
defer fasthttp.ReleaseRequest(req)
defer fasthttp.ReleaseResponse(resp)

req.SetRequestURI("http://example.com")
err := client.Do(req, resp)

gentleman client example:

cli := gentleman.New()
resp, err := cli.URL("http://example.com").Get().Send()
if err != nil {
    fmt.Printf("Request error: %s\n", err)
    return
}
fmt.Printf("Status: %d\n", resp.StatusCode)

fasthttp focuses on raw performance and low-level control, while gentleman provides a more user-friendly, feature-rich API for making HTTP requests. fasthttp is ideal for high-performance scenarios, but may require more manual work for complex operations. gentleman offers a more intuitive interface and additional features, but may not match fasthttp's raw performance in high-concurrency situations.

Convert Figma logo designs to code with AI

Visual Copilot

Introducing Visual Copilot: A new AI model to turn Figma designs to high quality code using your components.

Try Visual Copilot

README

gentleman GitHub release GoDoc Coverage Status Go Report Card Go Version

Full-featured, plugin-driven, middleware-oriented toolkit to easily create rich, versatile and composable HTTP clients in Go.

gentleman embraces extensibility and composition principles in order to provide a flexible way to easily create featured HTTP client layers based on built-in or third-party plugins that you can register and reuse across HTTP clients.

As an example, you can easily provide retry policy capabilities or dynamic server discovery in your HTTP clients simply attaching the retry or consul plugins.

Take a look to the examples, list of supported plugins, HTTP entities or middleware layer to get started.

For testing purposes, see baloo, an utility library for expressive end-to-end HTTP API testing, built on top of gentleman toolkit. For HTTP mocking, see gentleman-mock, which uses gock under the hood for easy and expressive HTTP client request mocking.

Versions

  • v2 - Latest version. Stable. Recommended.
  • v1 - First version. Stable. Actively maintained.

Features

  • Plugin driven architecture.
  • Simple, expressive, fluent API.
  • Idiomatic built on top of net/http package.
  • Context-aware hierarchical middleware layer supporting all the HTTP life cycle.
  • Built-in multiplexer for easy composition capabilities.
  • Easy to extend via plugins/middleware.
  • Ability to easily intercept and modify HTTP traffic on-the-fly.
  • Convenient helpers and abstractions over Go's HTTP primitives.
  • URL template path params.
  • Built-in JSON, XML and multipart bodies serialization and parsing.
  • Easy to test via HTTP mocking (e.g: gentleman-mock).
  • Supports data passing across plugins/middleware via its built-in context.
  • Fits good while building domain-specific HTTP API clients.
  • Easy to hack.
  • Dependency free.

Installation

go get -u gopkg.in/h2non/gentleman.v2

Requirements

  • Go 1.9+

Plugins

Name Docs Status Description
url Easily declare URL, base URL and path values in HTTP requests
auth Declare authorization headers in your requests
body Easily define bodies based on JSON, XML, strings, buffers or streams
bodytype Define body MIME type by alias
cookies Declare and store HTTP cookies easily
compression Helpers to define enable/disable HTTP compression
headers Manage HTTP headers easily
multipart Create multipart forms easily. Supports files and text fields
proxy Configure HTTP proxy servers
query Easily manage query params
redirect Easily configure a custom redirect policy
timeout Easily configure the HTTP timeouts (request, dial, TLS...)
transport Define a custom HTTP transport easily
tls Configure the TLS options used by the HTTP transport
retry Provide retry policy capabilities to your HTTP clients
mock Easy HTTP mocking using gock
consul Consul based server discovery with configurable retry/backoff policy

Community plugins

Name Docs Status Description
logger Easily log requests and responses

Send a PR to add your plugin to the list.

Creating plugins

You can create your own plugins for a wide variety of purposes, such as server discovery, custom HTTP tranport, modify any request/response param, intercept traffic, authentication and so on.

Plugins are essentially a set of middleware function handlers for one or multiple HTTP life cycle phases exposing a concrete interface consumed by gentleman middleware layer.

For more details about plugins see the plugin package and examples.

Also you can take a look to a plugin implementation example.

HTTP entities

gentleman provides two HTTP high level entities: Client and Request.

Each of these entities provides a common API and are both middleware capable, giving you the ability to plug in custom components with own logic into any of them.

gentleman was designed to provide strong reusability capabilities. This is mostly achieved via its built-in hierarchical, inheritance-based middleware layer.

The following list describes how inheritance hierarchy works and is used across gentleman's entities.

  • Client entity can inherit from other Client entity.
  • Request entity can inherit from a Client entity.
  • Client entity is mostly designed for reusability.
  • Client entity can create multiple Request entities who implicitly inherits from Client entity itself.
  • Request entity is designed to have specific HTTP request logic that is not typically reused.
  • Both Client and Request entities are full middleware capable interfaces.
  • Both Client and Request entities can be cloned in order to produce a copy but side-effects free new entity.

You can see an inheritance usage example here.

Middleware

gentleman is completely based on a hierarchical middleware layer based on plugins that executes one or multiple function handlers (aka plugin interface) providing a simple way to plug in intermediate custom logic in your HTTP client.

It supports multiple phases which represents the full HTTP request/response life cycle, giving you the ability to perform actions before and after an HTTP transaction happen, even intercepting and stopping it.

The middleware stack chain is executed in FIFO order designed for single thread model. Plugins can support goroutines, but plugins implementors should prevent data race issues due to concurrency in multithreading programming.

For more implementation details about the middleware layer, see the middleware package and examples.

Middleware phases

Supported middleware phases triggered by gentleman HTTP dispatcher:

  • request - Executed before a request is sent over the network.
  • response - Executed when the client receives the response, even if it failed.
  • error - Executed in case that an error ocurrs, support both injected or native error.
  • stop - Executed in case that the request has been manually stopped via middleware (e.g: after interception).
  • intercept - Executed in case that the request has been intercepted before network dialing.
  • before dial - Executed before a request is sent over the network.
  • after dial - Executed after the request dialing was done and the response has been received.

Note that the middleware layer has been designed for easy extensibility, therefore new phases may be added in the future and/or the developer could be able to trigger custom middleware phases if needed.

Feel free to fill an issue to discuss this capabilities in detail.

API

See godoc reference for detailed API documentation.

Subpackages

  • plugin - godoc - Plugin layer for gentleman.
  • mux - godoc - HTTP client multiplexer with built-in matchers.
  • middleware - godoc - Middleware layer used by gentleman.
  • context - godoc - HTTP context implementation for gentleman's middleware.
  • utils - godoc - HTTP utilities internally used.

Examples

See examples directory for featured examples.

Simple request

package main

import (
  "fmt"

  "gopkg.in/h2non/gentleman.v2"
)

func main() {
  // Create a new client
  cli := gentleman.New()

  // Define base URL
  cli.URL("http://httpbin.org")

  // Create a new request based on the current client
  req := cli.Request()

  // Define the URL path at request level
  req.Path("/headers")

  // Set a new header field
  req.SetHeader("Client", "gentleman")

  // Perform the request
  res, err := req.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
  }

  // Reads the whole body and returns it as string
  fmt.Printf("Body: %s", res.String())
}

Send JSON body

package main

import (
  "fmt"

  "gopkg.in/h2non/gentleman.v2"
  "gopkg.in/h2non/gentleman.v2/plugins/body"
)

func main() {
  // Create a new client
  cli := gentleman.New()

  // Define the Base URL
  cli.URL("http://httpbin.org/post")

  // Create a new request based on the current client
  req := cli.Request()

  // Method to be used
  req.Method("POST")

  // Define the JSON payload via body plugin
  data := map[string]string{"foo": "bar"}
  req.Use(body.JSON(data))

  // Perform the request
  res, err := req.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())
}

Composition via multiplexer

package main

import (
  "fmt"

  "gopkg.in/h2non/gentleman.v2"
  "gopkg.in/h2non/gentleman.v2/mux"
  "gopkg.in/h2non/gentleman.v2/plugins/url"
)

func main() {
  // Create a new client
  cli := gentleman.New()

  // Define the server url (must be first)
  cli.Use(url.URL("http://httpbin.org"))

  // Create a new multiplexer based on multiple matchers
  mx := mux.If(mux.Method("GET"), mux.Host("httpbin.org"))

  // Attach a custom plugin on the multiplexer that will be executed if the matchers passes
  mx.Use(url.Path("/headers"))

  // Attach the multiplexer on the main client
  cli.Use(mx)

  // 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())
}

License

MIT - Tomas Aparicio