Convert Figma logo to code with AI

imroc logoreq

Simple Go HTTP client with Black Magic

4,217
343
4,217
52

Top Related Projects

9,906

Simple HTTP and REST client library for Go

21,607

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

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

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

1,672

A Go HTTP client library for creating and sending API requests

Quick Overview

req is a simple and lightweight HTTP client library for Go, providing a more concise and expressive API compared to the standard net/http package. It aims to simplify common HTTP tasks and make writing HTTP-based applications more enjoyable.

Pros

  • Simplicity: req offers a more intuitive and concise API compared to the standard net/http package, making it easier to use for common HTTP tasks.
  • Flexibility: The library provides a wide range of features, including support for custom headers, query parameters, request bodies, and more.
  • Extensibility: req is designed to be easily extensible, with support for custom middleware and plugins.
  • Compatibility: The library is compatible with the standard net/http package, allowing seamless integration with existing code.

Cons

  • Limited Functionality: While req aims to simplify common HTTP tasks, it may not provide the same level of control and customization as the standard net/http package for more complex use cases.
  • Dependency Management: The library has a relatively small number of dependencies, but users may need to manage these dependencies carefully in their projects.
  • Lack of Widespread Adoption: Compared to other popular HTTP client libraries in the Go ecosystem, req may have a smaller user base and community support.
  • Potential Performance Overhead: The additional abstraction and features provided by req may introduce a small amount of performance overhead compared to the standard net/http package.

Code Examples

Here are a few examples of how to use the req library:

  1. Making a GET request:
resp, err := req.Get("https://api.example.com/users")
if err != nil {
    // Handle error
}
defer resp.Body.Close()

// Process the response
// ...
  1. Making a POST request with a JSON payload:
payload := map[string]interface{}{
    "name": "John Doe",
    "email": "john@example.com",
}

resp, err := req.Post("https://api.example.com/users", req.BodyJSON(payload))
if err != nil {
    // Handle error
}
defer resp.Body.Close()

// Process the response
// ...
  1. Adding custom headers:
resp, err := req.Get("https://api.example.com/users",
    req.Header("Authorization", "Bearer <your_token>"),
    req.Header("Content-Type", "application/json"),
)
if err != nil {
    // Handle error
}
defer resp.Body.Close()

// Process the response
// ...
  1. Using middleware:
// Define a custom middleware function
myMiddleware := func(next req.Handler) req.Handler {
    return func(r *req.Request) (*req.Response, error) {
        // Perform some custom logic before the request is executed
        // ...

        // Call the next middleware or the final handler
        return next(r)
    }
}

// Use the custom middleware
resp, err := req.Get("https://api.example.com/users",
    req.Use(myMiddleware),
)
if err != nil {
    // Handle error
}
defer resp.Body.Close()

// Process the response
// ...

Getting Started

To get started with the req library, you can install it using the Go package manager:

go get -u github.com/imroc/req

Once installed, you can import the library and start using it in your Go projects:

import "github.com/imroc/req"

func main() {
    resp, err := req.Get("https://api.example.com/users")
    if err != nil {
        // Handle error
    }
    defer resp.Body.Close()

    // Process the response
    // ...
}

For more detailed usage examples and documentation, please refer to the project's README on GitHub.

Competitor Comparisons

9,906

Simple HTTP and REST client library for Go

Pros of resty

  • More mature and widely adopted project with a larger community
  • Extensive documentation and examples available
  • Built-in support for advanced features like retries and backoff

Cons of resty

  • Slightly more complex API compared to req
  • Heavier dependency footprint
  • Less focus on performance optimization

Code Comparison

req:

resp, err := req.Get("https://api.example.com")
if err != nil {
    // Handle error
}
fmt.Println(resp.String())

resty:

resp, err := resty.New().R().Get("https://api.example.com")
if err != nil {
    // Handle error
}
fmt.Println(string(resp.Body()))

Both libraries offer similar functionality for making HTTP requests, but req aims for a simpler API and better performance, while resty provides more advanced features out of the box. req is newer and focuses on ease of use and efficiency, whereas resty has been around longer and offers a more comprehensive set of features. The choice between the two depends on the specific requirements of your project, such as the need for advanced features, performance considerations, and preference for API simplicity.

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, especially for high-concurrency scenarios
  • Lower memory usage and fewer allocations
  • Provides both client and server implementations

Cons of fasthttp

  • Less compatible with the standard library's net/http package
  • Steeper learning curve due to its unique API
  • May not support all HTTP features or edge cases

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)

req client example:

client := req.C()
resp, err := client.R().Get("http://example.com")

fasthttp focuses on performance optimization and memory efficiency, making it ideal for high-load applications. However, it sacrifices some compatibility and ease of use. req, on the other hand, provides a more user-friendly API that closely resembles the standard library, making it easier to adopt and use in existing projects. The choice between the two depends on specific project requirements, with fasthttp being better suited for performance-critical applications and req offering a more familiar and flexible approach for general-purpose HTTP client needs.

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

Pros of gorequest

  • Simpler API with method chaining for ease of use
  • Built-in support for multipart file uploads
  • Automatic retry functionality

Cons of gorequest

  • Less actively maintained (last commit over 3 years ago)
  • Fewer features compared to req (e.g., no HTTP/2 support)
  • Limited configuration options for advanced use cases

Code Comparison

gorequest:

resp, body, errs := gorequest.New().
    Get("http://example.com").
    End()

req:

resp, err := req.Get("http://example.com")
body, err := resp.ToString()

Key Differences

  • req offers more advanced features like HTTP/2 support, automatic compression, and dump capabilities
  • gorequest provides a more fluent API with method chaining
  • req has better performance and is more actively maintained
  • gorequest includes built-in retry functionality, while req requires manual implementation

Conclusion

While gorequest offers a simpler API and some convenient features, req is generally more powerful, performant, and actively maintained. The choice between the two depends on specific project requirements and developer preferences.

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

Pros of grequests

  • Simpler API, closely mimicking Python's requests library
  • Built-in session handling for improved performance
  • Supports both synchronous and asynchronous requests

Cons of grequests

  • Less actively maintained (last commit over 3 years ago)
  • Fewer features compared to req (e.g., no built-in retry mechanism)
  • Limited documentation and examples

Code Comparison

grequests:

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

req:

client := req.C()
resp, err := client.R().Get("http://example.com")
if err != nil {
    log.Fatalln("Unable to make request: ", err)
}
fmt.Println(resp.String())

Both libraries offer concise ways to make HTTP requests, but req provides more advanced features and customization options. grequests focuses on simplicity and familiarity for developers coming from Python, while req offers a more Go-idiomatic approach with additional functionality.

1,672

A Go HTTP client library for creating and sending API requests

Pros of sling

  • Fluent, method-chaining API for building and sending HTTP requests
  • Built-in support for JSON encoding/decoding
  • Lightweight with minimal dependencies

Cons of sling

  • Less feature-rich compared to req
  • Limited middleware support
  • Fewer convenience functions for common HTTP operations

Code Comparison

sling:

req := sling.New().Base("https://api.example.com/").Get("users")
var users []User
_, err := req.ReceiveSuccess(&users)

req:

var users []User
err := req.Get("https://api.example.com/users").Do().Into(&users)

Key Differences

  • sling uses a more explicit chaining approach, while req offers a more concise syntax
  • req provides more built-in features and convenience methods
  • sling focuses on simplicity and a minimal API surface
  • req offers more extensive middleware and plugin support

Both libraries aim to simplify HTTP requests in Go, but req provides a more comprehensive set of features and a slightly more user-friendly API. sling, on the other hand, offers a simpler and more lightweight approach that may be preferred for smaller projects or when minimal dependencies are desired.

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

req

Simple Go HTTP client with Black Magic

Build Status Go Report Card License GitHub Releases Mentioned in Awesome Go

Documentation

Full documentation is available on the official website: https://req.cool.

Features

  • Simple and Powerful: Simple and easy to use, providing rich client-level and request-level settings, all of which are intuitive and chainable methods.
  • Easy Debugging: Powerful and convenient debug utilities, including debug logs, performance traces, and even dump the complete request and response content (see Debugging).
  • Easy API Testing: API testing can be done with minimal code, no need to explicitly create any Request or Client, or even to handle errors (See Quick HTTP Test)
  • Smart by Default: Detect and decode to utf-8 automatically if possible to avoid garbled characters (See Auto Decode), marshal request body and unmarshal response body automatically according to the Content-Type.
  • Support Multiple HTTP Versions: Support HTTP/1.1, HTTP/2, and HTTP/3, and can automatically detect the server side and select the optimal HTTP version for requests, you can also force the protocol if you want (See Force HTTP version).
  • Support Retry: Support automatic request retry and is fully customizable (See Retry).
  • HTTP Fingerprinting: Support http fingerprint impersonation, so that we can access websites that prohibit crawler programs by identifying http fingerprints (See HTTP Fingerprint).
  • Multiple Authentication Methods: You can use HTTP Basic Auth, Bearer Auth Token and Digest Auth out of box (see Authentication).
  • Easy Download and Upload: You can download and upload files with simple request settings, and even set a callback to show real-time progress (See Download and Upload).
  • Exportable: req.Transport is exportable. Compared with http.Transport, it also supports HTTP3, dump content, middleware, etc. It can directly replace the Transport of http.Client in existing projects, and obtain more powerful functions with minimal code change.
  • Extensible: Support Middleware for Request, Response, Client and Transport (See Request and Response Middleware) and Client and Transport Middleware).

Get Started

Install

You first need Go installed (version 1.22+ is required), then you can use the below Go command to install req:

go get github.com/imroc/req/v3

Import

Import req to your code:

import "github.com/imroc/req/v3"

Basic Usage

# assume the following codes in main.go file
$ cat main.go
package main

import (
    "github.com/imroc/req/v3"
)

func main() {
    req.DevMode() // Treat the package name as a Client, enable development mode
    req.MustGet("https://httpbin.org/uuid") // Treat the package name as a Request, send GET request.

    req.EnableForceHTTP1() // Force using HTTP/1.1
    req.MustGet("https://httpbin.org/uuid")
}
$ go run main.go
2022/05/19 10:05:07.920113 DEBUG [req] HTTP/2 GET https://httpbin.org/uuid
:authority: httpbin.org
:method: GET
:path: /uuid
:scheme: https
user-agent: req/v3 (https://github.com/imroc/req/v3)
accept-encoding: gzip

:status: 200
date: Thu, 19 May 2022 02:05:08 GMT
content-type: application/json
content-length: 53
server: gunicorn/19.9.0
access-control-allow-origin: *
access-control-allow-credentials: true

{
  "uuid": "bd519208-35d1-4483-ad9f-e1555ae108ba"
}

2022/05/19 10:05:09.340974 DEBUG [req] HTTP/1.1 GET https://httpbin.org/uuid
GET /uuid HTTP/1.1
Host: httpbin.org
User-Agent: req/v3 (https://github.com/imroc/req/v3)
Accept-Encoding: gzip

HTTP/1.1 200 OK
Date: Thu, 19 May 2022 02:05:09 GMT
Content-Type: application/json
Content-Length: 53
Connection: keep-alive
Server: gunicorn/19.9.0
Access-Control-Allow-Origin: *
Access-Control-Allow-Credentials: true

{
  "uuid": "49b7f916-c6f3-49d4-a6d4-22ae93b71969"
}

The sample code above is good for quick testing purposes, which use DevMode() to see request details, and send requests using global wrapper methods that use the default client behind the scenes to initiate the request.

In production, it is recommended to explicitly create a client, and then use the same client to send all requests, please see other examples below.

Videos

The following is a series of video tutorials for req:

More

Check more introduction, tutorials, examples, best practices and API references on the official website.

Simple GET

package main

import (
	"fmt"
	"github.com/imroc/req/v3"
	"log"
)

func main() {
	client := req.C() // Use C() to create a client.
	resp, err := client.R(). // Use R() to create a request.
		Get("https://httpbin.org/uuid")
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println(resp)
}
{
  "uuid": "a4d4430d-0e5f-412f-88f5-722d84bc2a62"
}

Advanced GET

package main

import (
  "fmt"
  "github.com/imroc/req/v3"
  "log"
  "time"
)

type ErrorMessage struct {
  Message string `json:"message"`
}

type UserInfo struct {
  Name string `json:"name"`
  Blog string `json:"blog"`
}

func main() {
  client := req.C().
    SetUserAgent("my-custom-client"). // Chainable client settings.
    SetTimeout(5 * time.Second)

  var userInfo UserInfo
  var errMsg ErrorMessage
  resp, err := client.R().
    SetHeader("Accept", "application/vnd.github.v3+json"). // Chainable request settings.
    SetPathParam("username", "imroc"). // Replace path variable in url.
    SetSuccessResult(&userInfo). // Unmarshal response body into userInfo automatically if status code is between 200 and 299.
    SetErrorResult(&errMsg). // Unmarshal response body into errMsg automatically if status code >= 400.
    EnableDump(). // Enable dump at request level, only print dump content if there is an error or some unknown situation occurs to help troubleshoot.
    Get("https://api.github.com/users/{username}")

  if err != nil { // Error handling.
    log.Println("error:", err)
    log.Println("raw content:")
    log.Println(resp.Dump()) // Record raw content when error occurs.
    return
  }

  if resp.IsErrorState() { // Status code >= 400.
    fmt.Println(errMsg.Message) // Record error message returned.
    return
  }

  if resp.IsSuccessState() { // Status code is between 200 and 299.
    fmt.Printf("%s (%s)\n", userInfo.Name, userInfo.Blog)
    return
  }

  // Unknown status code.
  log.Println("unknown status", resp.Status)
  log.Println("raw content:")
  log.Println(resp.Dump()) // Record raw content when server returned unknown status code.
}

Normally it will output (SuccessState):

roc (https://imroc.cc)

More Advanced GET

You can set up a unified logic for error handling on the client, so that each time you send a request you only need to focus on the success situation, reducing duplicate code.

package main

import (
	"fmt"
	"github.com/imroc/req/v3"
	"log"
	"time"
)

type ErrorMessage struct {
	Message string `json:"message"`
}

func (msg *ErrorMessage) Error() string {
	return fmt.Sprintf("API Error: %s", msg.Message)
}

type UserInfo struct {
	Name string `json:"name"`
	Blog string `json:"blog"`
}

var client = req.C().
	SetUserAgent("my-custom-client"). // Chainable client settings.
	SetTimeout(5 * time.Second).
	EnableDumpEachRequest().
	SetCommonErrorResult(&ErrorMessage{}).
	OnAfterResponse(func(client *req.Client, resp *req.Response) error {
		if resp.Err != nil { // There is an underlying error, e.g. network error or unmarshal error.
			return nil
		}
		if errMsg, ok := resp.ErrorResult().(*ErrorMessage); ok {
			resp.Err = errMsg // Convert api error into go error
			return nil
		}
		if !resp.IsSuccessState() {
			// Neither a success response nor a error response, record details to help troubleshooting
			resp.Err = fmt.Errorf("bad status: %s\nraw content:\n%s", resp.Status, resp.Dump())
		}
		return nil
	})

func main() {
	var userInfo UserInfo
	resp, err := client.R().
		SetHeader("Accept", "application/vnd.github.v3+json"). // Chainable request settings
		SetPathParam("username", "imroc").
		SetSuccessResult(&userInfo). // Unmarshal response body into userInfo automatically if status code is between 200 and 299.
		Get("https://api.github.com/users/{username}")

	if err != nil { // Error handling.
		log.Println("error:", err)
		return
	}

	if resp.IsSuccessState() { // Status code is between 200 and 299.
		fmt.Printf("%s (%s)\n", userInfo.Name, userInfo.Blog)
	}
}

Simple POST

package main

import (
  "fmt"
  "github.com/imroc/req/v3"
  "log"
)

type Repo struct {
  Name string `json:"name"`
  Url  string `json:"url"`
}

type Result struct {
  Data string `json:"data"`
}

func main() {
  client := req.C().DevMode()
  var result Result

  resp, err := client.R().
    SetBody(&Repo{Name: "req", Url: "https://github.com/imroc/req"}).
    SetSuccessResult(&result).
    Post("https://httpbin.org/post")
  if err != nil {
    log.Fatal(err)
  }

  if !resp.IsSuccessState() {
    fmt.Println("bad response status:", resp.Status)
    return
  }
  fmt.Println("++++++++++++++++++++++++++++++++++++++++++++++++")
  fmt.Println("data:", result.Data)
  fmt.Println("++++++++++++++++++++++++++++++++++++++++++++++++")
}
2022/05/19 20:11:00.151171 DEBUG [req] HTTP/2 POST https://httpbin.org/post
:authority: httpbin.org
:method: POST
:path: /post
:scheme: https
user-agent: req/v3 (https://github.com/imroc/req/v3)
content-type: application/json; charset=utf-8
content-length: 55
accept-encoding: gzip

{"name":"req","website":"https://github.com/imroc/req"}

:status: 200
date: Thu, 19 May 2022 12:11:00 GMT
content-type: application/json
content-length: 651
server: gunicorn/19.9.0
access-control-allow-origin: *
access-control-allow-credentials: true

{
  "args": {},
  "data": "{\"name\":\"req\",\"website\":\"https://github.com/imroc/req\"}",
  "files": {},
  "form": {},
  "headers": {
    "Accept-Encoding": "gzip",
    "Content-Length": "55",
    "Content-Type": "application/json; charset=utf-8",
    "Host": "httpbin.org",
    "User-Agent": "req/v3 (https://github.com/imroc/req/v3)",
    "X-Amzn-Trace-Id": "Root=1-628633d4-7559d633152b4307288ead2e"
  },
  "json": {
    "name": "req",
    "website": "https://github.com/imroc/req"
  },
  "origin": "103.7.29.30",
  "url": "https://httpbin.org/post"
}

++++++++++++++++++++++++++++++++++++++++++++++++
data: {"name":"req","url":"https://github.com/imroc/req"}
++++++++++++++++++++++++++++++++++++++++++++++++

Do API Style

If you like, you can also use a Do API style like the following to make requests:

package main

import (
	"fmt"
	"github.com/imroc/req/v3"
)

type APIResponse struct {
	Origin string `json:"origin"`
	Url    string `json:"url"`
}

func main() {
	var resp APIResponse
	c := req.C().SetBaseURL("https://httpbin.org/post")
	err := c.Post().
		SetBody("hello").
		Do().
		Into(&resp)
	if err != nil {
		panic(err)
	}
	fmt.Println("My IP is", resp.Origin)
}
My IP is 182.138.155.113
  • The order of chain calls is more intuitive: first call Client to create a request with a specified Method, then use chain calls to set the request, then use Do() to fire the request, return Response, and finally call Response.Into to unmarshal response body into specified object.
  • Response.Into will return an error if an error occurs during sending the request or during unmarshalling.
  • The url of some APIs is fixed, and different types of requests are implemented by passing different bodies. In this scenario, Client.SetBaseURL can be used to set a unified url, and there is no need to set the url for each request when initiating a request. Of course, you can also call Request.SetURL to set it if you need it.

Build SDK With Req

Here is an example of building GitHub's SDK with req, using two styles (GetUserProfile_Style1, GetUserProfile_Style2).

import (
	"context"
	"fmt"
	"github.com/imroc/req/v3"
)

type ErrorMessage struct {
	Message string `json:"message"`
}

// Error implements go error interface.
func (msg *ErrorMessage) Error() string {
	return fmt.Sprintf("API Error: %s", msg.Message)
}

type GithubClient struct {
	*req.Client
}

func NewGithubClient() *GithubClient {
	return &GithubClient{
		Client: req.C().
			SetBaseURL("https://api.github.com").
			SetCommonErrorResult(&ErrorMessage{}).
			EnableDumpEachRequest().
			OnAfterResponse(func(client *req.Client, resp *req.Response) error {
				if resp.Err != nil { // There is an underlying error, e.g. network error or unmarshal error.
					return nil
				}
				if errMsg, ok := resp.ErrorResult().(*ErrorMessage); ok {
					resp.Err = errMsg // Convert api error into go error
					return nil
				}
				if !resp.IsSuccessState() {
					// Neither a success response nor a error response, record details to help troubleshooting
					resp.Err = fmt.Errorf("bad status: %s\nraw content:\n%s", resp.Status, resp.Dump())
				}
				return nil
			}),
	}
}

type UserProfile struct {
	Name string `json:"name"`
	Blog string `json:"blog"`
}

// GetUserProfile_Style1 returns the user profile for the specified user.
// Github API doc: https://docs.github.com/en/rest/users/users#get-a-user
func (c *GithubClient) GetUserProfile_Style1(ctx context.Context, username string) (user *UserProfile, err error) {
	_, err = c.R().
		SetContext(ctx).
		SetPathParam("username", username).
		SetSuccessResult(&user).
		Get("/users/{username}")
	return
}

// GetUserProfile_Style2 returns the user profile for the specified user.
// Github API doc: https://docs.github.com/en/rest/users/users#get-a-user
func (c *GithubClient) GetUserProfile_Style2(ctx context.Context, username string) (user *UserProfile, err error) {
	err = c.Get("/users/{username}").
		SetPathParam("username", username).
		Do(ctx).
		Into(&user)
	return
}

Contributing

If you have a bug report or feature request, you can open an issue, and pull requests are also welcome.

Contact

If you have questions, feel free to reach out to us in the following ways:

Sponsors

If you like req and it really helps you, feel free to reward me with a cup of coffee, and don't forget to mention your github id.


Wechat

Alipay

Many thanks to the following sponsors:


M-Cosmosss 🥇

aadog 🥈

License

Req released under MIT license, refer LICENSE file.