Simple HTTP and REST client library for Go

Overview

Resty

Simple HTTP and REST client library for Go (inspired by Ruby rest-client)

Features section describes in detail about Resty capabilities

Build Status Code Coverage Go Report Card Release Version GoDoc License Mentioned in Awesome Go

Resty Communication Channels

Chat on Gitter - Resty Community Twitter @go_resty

News

  • v2.4.0 released and tagged on Jan 11, 2021.
  • v2.3.0 released and tagged on May 20, 2020.
  • v2.0.0 released and tagged on Jul 16, 2019.
  • v1.12.0 released and tagged on Feb 27, 2019.
  • v1.0 released and tagged on Sep 25, 2017. - Resty's first version was released on Sep 15, 2015 then it grew gradually as a very handy and helpful library. Its been a two years since first release. I'm very thankful to Resty users and its contributors.

Features

  • GET, POST, PUT, DELETE, HEAD, PATCH, OPTIONS, etc.
  • Simple and chainable methods for settings and request
  • Request Body can be string, []byte, struct, map, slice and io.Reader too
    • Auto detects Content-Type
    • Buffer less processing for io.Reader
    • Native *http.Request instance may be accessed during middleware and request execution via Request.RawRequest
    • Request Body can be read multiple times via Request.RawRequest.GetBody()
  • Response object gives you more possibility
    • Access as []byte array - response.Body() OR Access as string - response.String()
    • Know your response.Time() and when we response.ReceivedAt()
  • Automatic marshal and unmarshal for JSON and XML content type
  • Easy to upload one or more file(s) via multipart/form-data
    • Auto detects file content type
  • Request URL Path Params (aka URI Params)
  • Backoff Retry Mechanism with retry condition function reference
  • Resty client HTTP & REST Request and Response middlewares
  • Request.SetContext supported
  • Authorization option of BasicAuth and Bearer token
  • Set request ContentLength value for all request or particular request
  • Custom Root Certificates and Client Certificates
  • Download/Save HTTP response directly into File, like curl -o flag. See SetOutputDirectory & SetOutput.
  • Cookies for your request and CookieJar support
  • SRV Record based request instead of Host URL
  • Client settings like Timeout, RedirectPolicy, Proxy, TLSClientConfig, Transport, etc.
  • Optionally allows GET request with payload, see SetAllowGetMethodPayload
  • Supports registering external JSON library into resty, see how to use
  • Exposes Response reader without reading response (no auto-unmarshaling) if need be, see how to use
  • Option to specify expected Content-Type when response Content-Type header missing. Refer to #92
  • Resty design
    • Have client level settings & options and also override at Request level if you want to
    • Request and Response middleware
    • Create Multiple clients if you want to resty.New()
    • Supports http.RoundTripper implementation, see SetTransport
    • goroutine concurrent safe
    • Resty Client trace, see Client.EnableTrace and Request.EnableTrace
      • Since v2.4.0, trace info contains a RequestAttempt value, and the Request object contains an Attempt attribute
    • Debug mode - clean and informative logging presentation
    • Gzip - Go does it automatically also resty has fallback handling too
    • Works fine with HTTP/2 and HTTP/1.1
  • Bazel support
  • Easily mock Resty for testing, for e.g.
  • Well tested client library

Included Batteries

  • Redirect Policies - see how to use
    • NoRedirectPolicy
    • FlexibleRedirectPolicy
    • DomainCheckRedirectPolicy
    • etc. more info
  • Retry Mechanism how to use
    • Backoff Retry
    • Conditional Retry
  • SRV Record based request instead of Host URL how to use
  • etc (upcoming - throw your idea's here).

Supported Go Versions

Initially Resty started supporting go modules since v1.10.0 release.

Starting Resty v2 and higher versions, it fully embraces go modules package release. It requires a Go version capable of understanding /vN suffixed imports:

  • 1.9.7+
  • 1.10.3+
  • 1.11+

It might be beneficial for your project 😄

Resty author also published following projects for Go Community.

  • aah framework - A secure, flexible, rapid Go web framework.
  • THUMBAI - Go Mod Repository, Go Vanity Service and Simple Proxy Server.
  • go-model - Robust & Easy to use model mapper and utility methods for Go struct.

Installation

# Go Modules
require github.com/go-resty/resty/v2 v2.4.0

Usage

The following samples will assist you to become as comfortable as possible with resty library.

// Import resty into your code and refer it as `resty`.
import "github.com/go-resty/resty/v2"

Simple GET

// Create a Resty Client
client := resty.New()

resp, err := client.R().
    EnableTrace().
    Get("https://httpbin.org/get")

// Explore response object
fmt.Println("Response Info:")
fmt.Println("  Error      :", err)
fmt.Println("  Status Code:", resp.StatusCode())
fmt.Println("  Status     :", resp.Status())
fmt.Println("  Proto      :", resp.Proto())
fmt.Println("  Time       :", resp.Time())
fmt.Println("  Received At:", resp.ReceivedAt())
fmt.Println("  Body       :\n", resp)
fmt.Println()

// Explore trace info
fmt.Println("Request Trace Info:")
ti := resp.Request.TraceInfo()
fmt.Println("  DNSLookup     :", ti.DNSLookup)
fmt.Println("  ConnTime      :", ti.ConnTime)
fmt.Println("  TCPConnTime   :", ti.TCPConnTime)
fmt.Println("  TLSHandshake  :", ti.TLSHandshake)
fmt.Println("  ServerTime    :", ti.ServerTime)
fmt.Println("  ResponseTime  :", ti.ResponseTime)
fmt.Println("  TotalTime     :", ti.TotalTime)
fmt.Println("  IsConnReused  :", ti.IsConnReused)
fmt.Println("  IsConnWasIdle :", ti.IsConnWasIdle)
fmt.Println("  ConnIdleTime  :", ti.ConnIdleTime)
fmt.Println("  RequestAttempt:", ti.RequestAttempt)
fmt.Println("  RemoteAddr    :", ti.RemoteAddr.String())

/* Output
Response Info:
  Error      : <nil>
  Status Code: 200
  Status     : 200 OK
  Proto      : HTTP/2.0
  Time       : 457.034718ms
  Received At: 2020-09-14 15:35:29.784681 -0700 PDT m=+0.458137045
  Body       :
  {
    "args": {},
    "headers": {
      "Accept-Encoding": "gzip",
      "Host": "httpbin.org",
      "User-Agent": "go-resty/2.4.0 (https://github.com/go-resty/resty)",
      "X-Amzn-Trace-Id": "Root=1-5f5ff031-000ff6292204aa6898e4de49"
    },
    "origin": "0.0.0.0",
    "url": "https://httpbin.org/get"
  }

Request Trace Info:
  DNSLookup     : 4.074657ms
  ConnTime      : 381.709936ms
  TCPConnTime   : 77.428048ms
  TLSHandshake  : 299.623597ms
  ServerTime    : 75.414703ms
  ResponseTime  : 79.337µs
  TotalTime     : 457.034718ms
  IsConnReused  : false
  IsConnWasIdle : false
  ConnIdleTime  : 0s
  RequestAttempt: 1
  RemoteAddr    : 3.221.81.55:443
*/

Enhanced GET

// Create a Resty Client
client := resty.New()

resp, err := client.R().
      SetQueryParams(map[string]string{
          "page_no": "1",
          "limit": "20",
          "sort":"name",
          "order": "asc",
          "random":strconv.FormatInt(time.Now().Unix(), 10),
      }).
      SetHeader("Accept", "application/json").
      SetAuthToken("BC594900518B4F7EAC75BD37F019E08FBC594900518B4F7EAC75BD37F019E08F").
      Get("/search_result")


// Sample of using Request.SetQueryString method
resp, err := client.R().
      SetQueryString("productId=232&template=fresh-sample&cat=resty&source=google&kw=buy a lot more").
      SetHeader("Accept", "application/json").
      SetAuthToken("BC594900518B4F7EAC75BD37F019E08FBC594900518B4F7EAC75BD37F019E08F").
      Get("/show_product")


// If necessary, you can force response content type to tell Resty to parse a JSON response into your struct
resp, err := client.R().
      SetResult(result).
      ForceContentType("application/json").
      Get("v2/alpine/manifests/latest")

Various POST method combinations

// Create a Resty Client
client := resty.New()

// POST JSON string
// No need to set content type, if you have client level setting
resp, err := client.R().
      SetHeader("Content-Type", "application/json").
      SetBody(`{"username":"testuser", "password":"testpass"}`).
      SetResult(&AuthSuccess{}).    // or SetResult(AuthSuccess{}).
      Post("https://myapp.com/login")

// POST []byte array
// No need to set content type, if you have client level setting
resp, err := client.R().
      SetHeader("Content-Type", "application/json").
      SetBody([]byte(`{"username":"testuser", "password":"testpass"}`)).
      SetResult(&AuthSuccess{}).    // or SetResult(AuthSuccess{}).
      Post("https://myapp.com/login")

// POST Struct, default is JSON content type. No need to set one
resp, err := client.R().
      SetBody(User{Username: "testuser", Password: "testpass"}).
      SetResult(&AuthSuccess{}).    // or SetResult(AuthSuccess{}).
      SetError(&AuthError{}).       // or SetError(AuthError{}).
      Post("https://myapp.com/login")

// POST Map, default is JSON content type. No need to set one
resp, err := client.R().
      SetBody(map[string]interface{}{"username": "testuser", "password": "testpass"}).
      SetResult(&AuthSuccess{}).    // or SetResult(AuthSuccess{}).
      SetError(&AuthError{}).       // or SetError(AuthError{}).
      Post("https://myapp.com/login")

// POST of raw bytes for file upload. For example: upload file to Dropbox
fileBytes, _ := ioutil.ReadFile("/Users/jeeva/mydocument.pdf")

// See we are not setting content-type header, since go-resty automatically detects Content-Type for you
resp, err := client.R().
      SetBody(fileBytes).
      SetContentLength(true).          // Dropbox expects this value
      SetAuthToken("<your-auth-token>").
      SetError(&DropboxError{}).       // or SetError(DropboxError{}).
      Post("https://content.dropboxapi.com/1/files_put/auto/resty/mydocument.pdf") // for upload Dropbox supports PUT too

// Note: resty detects Content-Type for request body/payload if content type header is not set.
//   * For struct and map data type defaults to 'application/json'
//   * Fallback is plain text content type

Sample PUT

You can use various combinations of PUT method call like demonstrated for POST.

// Note: This is one sample of PUT method usage, refer POST for more combination

// Create a Resty Client
client := resty.New()

// Request goes as JSON content type
// No need to set auth token, error, if you have client level settings
resp, err := client.R().
      SetBody(Article{
        Title: "go-resty",
        Content: "This is my article content, oh ya!",
        Author: "Jeevanandam M",
        Tags: []string{"article", "sample", "resty"},
      }).
      SetAuthToken("C6A79608-782F-4ED0-A11D-BD82FAD829CD").
      SetError(&Error{}).       // or SetError(Error{}).
      Put("https://myapp.com/article/1234")

Sample PATCH

You can use various combinations of PATCH method call like demonstrated for POST.

// Note: This is one sample of PUT method usage, refer POST for more combination

// Create a Resty Client
client := resty.New()

// Request goes as JSON content type
// No need to set auth token, error, if you have client level settings
resp, err := client.R().
      SetBody(Article{
        Tags: []string{"new tag1", "new tag2"},
      }).
      SetAuthToken("C6A79608-782F-4ED0-A11D-BD82FAD829CD").
      SetError(&Error{}).       // or SetError(Error{}).
      Patch("https://myapp.com/articles/1234")

Sample DELETE, HEAD, OPTIONS

// Create a Resty Client
client := resty.New()

// DELETE a article
// No need to set auth token, error, if you have client level settings
resp, err := client.R().
      SetAuthToken("C6A79608-782F-4ED0-A11D-BD82FAD829CD").
      SetError(&Error{}).       // or SetError(Error{}).
      Delete("https://myapp.com/articles/1234")

// DELETE a articles with payload/body as a JSON string
// No need to set auth token, error, if you have client level settings
resp, err := client.R().
      SetAuthToken("C6A79608-782F-4ED0-A11D-BD82FAD829CD").
      SetError(&Error{}).       // or SetError(Error{}).
      SetHeader("Content-Type", "application/json").
      SetBody(`{article_ids: [1002, 1006, 1007, 87683, 45432] }`).
      Delete("https://myapp.com/articles")

// HEAD of resource
// No need to set auth token, if you have client level settings
resp, err := client.R().
      SetAuthToken("C6A79608-782F-4ED0-A11D-BD82FAD829CD").
      Head("https://myapp.com/videos/hi-res-video")

// OPTIONS of resource
// No need to set auth token, if you have client level settings
resp, err := client.R().
      SetAuthToken("C6A79608-782F-4ED0-A11D-BD82FAD829CD").
      Options("https://myapp.com/servers/nyc-dc-01")

Multipart File(s) upload

Using io.Reader

profileImgBytes, _ := ioutil.ReadFile("/Users/jeeva/test-img.png")
notesBytes, _ := ioutil.ReadFile("/Users/jeeva/text-file.txt")

// Create a Resty Client
client := resty.New()

resp, err := client.R().
      SetFileReader("profile_img", "test-img.png", bytes.NewReader(profileImgBytes)).
      SetFileReader("notes", "text-file.txt", bytes.NewReader(notesBytes)).
      SetFormData(map[string]string{
          "first_name": "Jeevanandam",
          "last_name": "M",
      }).
      Post("http://myapp.com/upload")

Using File directly from Path

// Create a Resty Client
client := resty.New()

// Single file scenario
resp, err := client.R().
      SetFile("profile_img", "/Users/jeeva/test-img.png").
      Post("http://myapp.com/upload")

// Multiple files scenario
resp, err := client.R().
      SetFiles(map[string]string{
        "profile_img": "/Users/jeeva/test-img.png",
        "notes": "/Users/jeeva/text-file.txt",
      }).
      Post("http://myapp.com/upload")

// Multipart of form fields and files
resp, err := client.R().
      SetFiles(map[string]string{
        "profile_img": "/Users/jeeva/test-img.png",
        "notes": "/Users/jeeva/text-file.txt",
      }).
      SetFormData(map[string]string{
        "first_name": "Jeevanandam",
        "last_name": "M",
        "zip_code": "00001",
        "city": "my city",
        "access_token": "C6A79608-782F-4ED0-A11D-BD82FAD829CD",
      }).
      Post("http://myapp.com/profile")

Sample Form submission

// Create a Resty Client
client := resty.New()

// just mentioning about POST as an example with simple flow
// User Login
resp, err := client.R().
      SetFormData(map[string]string{
        "username": "jeeva",
        "password": "mypass",
      }).
      Post("http://myapp.com/login")

// Followed by profile update
resp, err := client.R().
      SetFormData(map[string]string{
        "first_name": "Jeevanandam",
        "last_name": "M",
        "zip_code": "00001",
        "city": "new city update",
      }).
      Post("http://myapp.com/profile")

// Multi value form data
criteria := url.Values{
  "search_criteria": []string{"book", "glass", "pencil"},
}
resp, err := client.R().
      SetFormDataFromValues(criteria).
      Post("http://myapp.com/search")

Save HTTP Response into File

// Create a Resty Client
client := resty.New()

// Setting output directory path, If directory not exists then resty creates one!
// This is optional one, if you're planning using absoule path in
// `Request.SetOutput` and can used together.
client.SetOutputDirectory("/Users/jeeva/Downloads")

// HTTP response gets saved into file, similar to curl -o flag
_, err := client.R().
          SetOutput("plugin/ReplyWithHeader-v5.1-beta.zip").
          Get("http://bit.ly/1LouEKr")

// OR using absolute path
// Note: output directory path is not used for absolute path
_, err := client.R().
          SetOutput("/MyDownloads/plugin/ReplyWithHeader-v5.1-beta.zip").
          Get("http://bit.ly/1LouEKr")

Request URL Path Params

Resty provides easy to use dynamic request URL path params. Params can be set at client and request level. Client level params value can be overridden at request level.

// Create a Resty Client
client := resty.New()

client.R().SetPathParams(map[string]string{
   "userId": "[email protected]",
   "subAccountId": "100002",
}).
Get("/v1/users/{userId}/{subAccountId}/details")

// Result:
//   Composed URL - /v1/users/[email protected]/100002/details

Request and Response Middleware

Resty provides middleware ability to manipulate for Request and Response. It is more flexible than callback approach.

// Create a Resty Client
client := resty.New()

// Registering Request Middleware
client.OnBeforeRequest(func(c *resty.Client, req *resty.Request) error {
    // Now you have access to Client and current Request object
    // manipulate it as per your need

    return nil  // if its success otherwise return error
  })

// Registering Response Middleware
client.OnAfterResponse(func(c *resty.Client, resp *resty.Response) error {
    // Now you have access to Client and current Response object
    // manipulate it as per your need

    return nil  // if its success otherwise return error
  })

OnError Hooks

Resty provides OnError hooks that may be called because:

  • The client failed to send the request due to connection timeout, TLS handshake failure, etc...
  • The request was retried the maximum amount of times, and still failed.

If there was a response from the server, the original error will be wrapped in *resty.ResponseError which contains the last response received.

// Create a Resty Client
client := resty.New()

client.OnError(func(req *resty.Request, err error) {
  if v, ok := err.(*resty.ResponseError); ok {
    // v.Response contains the last response from the server
    // v.Err contains the original error
  }
  // Log the error, increment a metric, etc...
})

Redirect Policy

Resty provides few ready to use redirect policy(s) also it supports multiple policies together.

// Create a Resty Client
client := resty.New()

// Assign Client Redirect Policy. Create one as per you need
client.SetRedirectPolicy(resty.FlexibleRedirectPolicy(15))

// Wanna multiple policies such as redirect count, domain name check, etc
client.SetRedirectPolicy(resty.FlexibleRedirectPolicy(20),
                        resty.DomainCheckRedirectPolicy("host1.com", "host2.org", "host3.net"))
Custom Redirect Policy

Implement RedirectPolicy interface and register it with resty client. Have a look redirect.go for more information.

// Create a Resty Client
client := resty.New()

// Using raw func into resty.SetRedirectPolicy
client.SetRedirectPolicy(resty.RedirectPolicyFunc(func(req *http.Request, via []*http.Request) error {
  // Implement your logic here

  // return nil for continue redirect otherwise return error to stop/prevent redirect
  return nil
}))

//---------------------------------------------------

// Using struct create more flexible redirect policy
type CustomRedirectPolicy struct {
  // variables goes here
}

func (c *CustomRedirectPolicy) Apply(req *http.Request, via []*http.Request) error {
  // Implement your logic here

  // return nil for continue redirect otherwise return error to stop/prevent redirect
  return nil
}

// Registering in resty
client.SetRedirectPolicy(CustomRedirectPolicy{/* initialize variables */})

Custom Root Certificates and Client Certificates

// Create a Resty Client
client := resty.New()

// Custom Root certificates, just supply .pem file.
// you can add one or more root certificates, its get appended
client.SetRootCertificate("/path/to/root/pemFile1.pem")
client.SetRootCertificate("/path/to/root/pemFile2.pem")
// ... and so on!

// Adding Client Certificates, you add one or more certificates
// Sample for creating certificate object
// Parsing public/private key pair from a pair of files. The files must contain PEM encoded data.
cert1, err := tls.LoadX509KeyPair("certs/client.pem", "certs/client.key")
if err != nil {
  log.Fatalf("ERROR client certificate: %s", err)
}
// ...

// You add one or more certificates
client.SetCertificates(cert1, cert2, cert3)

Custom Root Certificates and Client Certificates from string

// Custom Root certificates from string
// You can pass you certificates throught env variables as strings
// you can add one or more root certificates, its get appended
client.SetRootCertificateFromString("-----BEGIN CERTIFICATE-----content-----END CERTIFICATE-----")
client.SetRootCertificateFromString("-----BEGIN CERTIFICATE-----content-----END CERTIFICATE-----")
// ... and so on!

// Adding Client Certificates, you add one or more certificates
// Sample for creating certificate object
// Parsing public/private key pair from a pair of files. The files must contain PEM encoded data.
cert1, err := tls.X509KeyPair([]byte("-----BEGIN CERTIFICATE-----content-----END CERTIFICATE-----"), []byte("-----BEGIN CERTIFICATE-----content-----END CERTIFICATE-----"))
if err != nil {
  log.Fatalf("ERROR client certificate: %s", err)
}
// ...

// You add one or more certificates
client.SetCertificates(cert1, cert2, cert3)

Proxy Settings - Client as well as at Request Level

Default Go supports Proxy via environment variable HTTP_PROXY. Resty provides support via SetProxy & RemoveProxy. Choose as per your need.

Client Level Proxy settings applied to all the request

// Create a Resty Client
client := resty.New()

// Setting a Proxy URL and Port
client.SetProxy("http://proxyserver:8888")

// Want to remove proxy setting
client.RemoveProxy()

Retries

Resty uses backoff to increase retry intervals after each attempt.

Usage example:

// Create a Resty Client
client := resty.New()

// Retries are configured per client
client.
    // Set retry count to non zero to enable retries
    SetRetryCount(3).
    // You can override initial retry wait time.
    // Default is 100 milliseconds.
    SetRetryWaitTime(5 * time.Second).
    // MaxWaitTime can be overridden as well.
    // Default is 2 seconds.
    SetRetryMaxWaitTime(20 * time.Second).
    // SetRetryAfter sets callback to calculate wait time between retries.
    // Default (nil) implies exponential backoff with jitter
    SetRetryAfter(func(client *resty.Client, resp *resty.Response) (time.Duration, error) {
        return 0, errors.New("quota exceeded")
    })

Above setup will result in resty retrying requests returned non nil error up to 3 times with delay increased after each attempt.

You can optionally provide client with custom retry conditions:

// Create a Resty Client
client := resty.New()

client.AddRetryCondition(
    // RetryConditionFunc type is for retry condition function
    // input: non-nil Response OR request execution error
    func(r *resty.Response, err error) bool {
        return r.StatusCode() == http.StatusTooManyRequests
    },
)

Above example will make resty retry requests ended with 429 Too Many Requests status code.

Multiple retry conditions can be added.

It is also possible to use resty.Backoff(...) to get arbitrary retry scenarios implemented. Reference.

Allow GET request with Payload

// Create a Resty Client
client := resty.New()

// Allow GET request with Payload. This is disabled by default.
client.SetAllowGetMethodPayload(true)

Wanna Multiple Clients

// Here you go!
// Client 1
client1 := resty.New()
client1.R().Get("http://httpbin.org")
// ...

// Client 2
client2 := resty.New()
client2.R().Head("http://httpbin.org")
// ...

// Bend it as per your need!!!

Remaining Client Settings & its Options

// Create a Resty Client
client := resty.New()

// Unique settings at Client level
//--------------------------------
// Enable debug mode
client.SetDebug(true)

// Assign Client TLSClientConfig
// One can set custom root-certificate. Refer: http://golang.org/pkg/crypto/tls/#example_Dial
client.SetTLSClientConfig(&tls.Config{ RootCAs: roots })

// or One can disable security check (https)
client.SetTLSClientConfig(&tls.Config{ InsecureSkipVerify: true })

// Set client timeout as per your need
client.SetTimeout(1 * time.Minute)


// You can override all below settings and options at request level if you want to
//--------------------------------------------------------------------------------
// Host URL for all request. So you can use relative URL in the request
client.SetHostURL("http://httpbin.org")

// Headers for all request
client.SetHeader("Accept", "application/json")
client.SetHeaders(map[string]string{
        "Content-Type": "application/json",
        "User-Agent": "My custom User Agent String",
      })

// Cookies for all request
client.SetCookie(&http.Cookie{
      Name:"go-resty",
      Value:"This is cookie value",
      Path: "/",
      Domain: "sample.com",
      MaxAge: 36000,
      HttpOnly: true,
      Secure: false,
    })
client.SetCookies(cookies)

// URL query parameters for all request
client.SetQueryParam("user_id", "00001")
client.SetQueryParams(map[string]string{ // sample of those who use this manner
      "api_key": "api-key-here",
      "api_secert": "api-secert",
    })
client.R().SetQueryString("productId=232&template=fresh-sample&cat=resty&source=google&kw=buy a lot more")

// Form data for all request. Typically used with POST and PUT
client.SetFormData(map[string]string{
    "access_token": "BC594900-518B-4F7E-AC75-BD37F019E08F",
  })

// Basic Auth for all request
client.SetBasicAuth("myuser", "mypass")

// Bearer Auth Token for all request
client.SetAuthToken("BC594900518B4F7EAC75BD37F019E08FBC594900518B4F7EAC75BD37F019E08F")

// Enabling Content length value for all request
client.SetContentLength(true)

// Registering global Error object structure for JSON/XML request
client.SetError(&Error{})    // or resty.SetError(Error{})

Unix Socket

unixSocket := "/var/run/my_socket.sock"

// Create a Go's http.Transport so we can set it in resty.
transport := http.Transport{
	Dial: func(_, _ string) (net.Conn, error) {
		return net.Dial("unix", unixSocket)
	},
}

// Create a Resty Client
client := resty.New()

// Set the previous transport that we created, set the scheme of the communication to the
// socket and set the unixSocket as the HostURL.
client.SetTransport(&transport).SetScheme("http").SetHostURL(unixSocket)

// No need to write the host's URL on the request, just the path.
client.R().Get("/index.html")

Bazel support

Resty can be built, tested and depended upon via Bazel. For example, to run all tests:

bazel test :go_default_test

Mocking http requests using httpmock library

In order to mock the http requests when testing your application you could use the httpmock library.

When using the default resty client, you should pass the client to the library as follow:

// Create a Resty Client
client := resty.New()

// Get the underlying HTTP Client and set it to Mock
httpmock.ActivateNonDefault(client.GetClient())

More detailed example of mocking resty http requests using ginko could be found here.

Versioning

Resty releases versions according to Semantic Versioning

  • Resty v2 does not use gopkg.in service for library versioning.
  • Resty fully adapted to go mod capabilities since v1.10.0 release.
  • Resty v1 series was using gopkg.in to provide versioning. gopkg.in/resty.vX points to appropriate tagged versions; X denotes version series number and it's a stable release for production use. For e.g. gopkg.in/resty.v0.
  • Development takes place at the master branch. Although the code in master should always compile and test successfully, it might break API's. I aim to maintain backwards compatibility, but sometimes API's and behavior might be changed to fix a bug.

Contribution

I would welcome your contribution! If you find any improvement or issue you want to fix, feel free to send a pull request, I like pull requests that include test cases for fix/enhancement. I have done my best to bring pretty good code coverage. Feel free to write tests.

BTW, I'd like to know what you think about Resty. Kindly open an issue or send me an email; it'd mean a lot to me.

Creator

Jeevanandam M. ([email protected])

Core Team

Have a look on Members page.

Contributors

Have a look on Contributors page.

License

Resty released under MIT license, refer LICENSE file.

Issues
  • Collecting Inputs for Resty v2.0 and Plan the release

    Collecting Inputs for Resty v2.0 and Plan the release

    The goal of this thread to collect feedback's from resty users and plan v2.0.0 release. Action items get recorded here #167.

    • Things could be improved
    • Things could be added (generalized one's not specific use case)
    • Things could be removed

    Share your resty experiences for upcoming v2.0.0

    interaction 
    opened by jeevatkm 46
  • Go Module

    Go Module

    The documentation suggests that one should use resty as follows:

    import "gopkg.in/resty.v1"
    

    (https://github.com/go-resty/resty/blob/ec17de1c59a99e0743dac77aaab6435f364fdc42/README.md#usage)

    But this brakes with Go modules, because go.mod declares the module as follows:

    https://github.com/go-resty/resty/blob/ec17de1c59a99e0743dac77aaab6435f364fdc42/go.mod#L1

    This causes troubles when I try to compile code with go11.1rc2 and go modules enabled.

    All is fine when I import resty like this:

    import "github.com/go-resty/resty"
    

    Now there are two options:

    a) Adjust the documentation and suggest to import "github.com/go-resty/resty" b) Adjust the go.mod to be module "gopkg.in/resty.v1

    Option (a) is good for all new project that start with go modules right away, but it's backward incompatible. Option (b) would be good for projects that used plain go get or dep until now and upgrade to go.mod, because they don't have to change all the import statements. There are no further drawbacks, except that this option needs a new release with an updated go.mod.

    bug documentation support 
    opened by cimnine 32
  • Potential race in resty with combination of retries and the buffers pool

    Potential race in resty with combination of retries and the buffers pool

    We have a golang project that uses resty as the http client.
    We started using the golang race detector in our staging environment and encountered the following race errors:

    ==================
    WARNING: DATA RACE
    Write at 0x00c00025e610 by goroutine 149:
      bytes.(*Buffer).Read()
          /usr/local/go/src/bytes/buffer.go:299 +0x4a
      io/ioutil.(*nopCloser).Read()
          <autogenerated>:1 +0x87
      net/http.(*http2clientStream).writeRequestBody()
          /usr/local/go/src/net/http/h2_bundle.go:7825 +0x635
      net/http.(*http2Transport).getBodyWriterState.func1()
          /usr/local/go/src/net/http/h2_bundle.go:9040 +0x13d
    
    Previous write at 0x00c00025e610 by goroutine 109:
      bytes.(*Buffer).Read()
          /usr/local/go/src/bytes/buffer.go:299 +0x4a
      io/ioutil.(*nopCloser).Read()
          <autogenerated>:1 +0x87
      net/http.(*http2clientStream).writeRequestBody()
          /usr/local/go/src/net/http/h2_bundle.go:7825 +0x635
      net/http.(*http2Transport).getBodyWriterState.func1()
          /usr/local/go/src/net/http/h2_bundle.go:9040 +0x13d
    
    Goroutine 149 (running) created at:
      net/http.http2bodyWriterState.scheduleBodyWrite()
          /usr/local/go/src/net/http/h2_bundle.go:9087 +0xb8
      net/http.(*http2ClientConn).roundTrip()
          /usr/local/go/src/net/http/h2_bundle.go:7626 +0x81b
      net/http.(*http2Transport).RoundTripOpt()
          /usr/local/go/src/net/http/h2_bundle.go:7037 +0x22d
      net/http.(*http2Transport).RoundTrip()
          /usr/local/go/src/net/http/h2_bundle.go:6999 +0x4b
      net/http.(*Transport).roundTrip()
          /usr/local/go/src/net/http/transport.go:463 +0xa21
      net/http.(*Transport).RoundTrip()
          /usr/local/go/src/net/http/roundtrip.go:17 +0x42
      net/http.send()
          /usr/local/go/src/net/http/client.go:250 +0x304
      net/http.(*Client).send()
          /usr/local/go/src/net/http/client.go:174 +0x1ca
      net/http.(*Client).do()
          /usr/local/go/src/net/http/client.go:641 +0x53a
      net/http.(*Client).Do()
          /usr/local/go/src/net/http/client.go:509 +0x42
      github.com/Rookout/golib/vendor/gopkg.in/resty%2ev1.(*Client).execute()
          /go/src/github.com/Rookout/golib/vendor/gopkg.in/resty.v1/client.go:819 +0x3dd
      github.com/Rookout/golib/vendor/gopkg.in/resty%2ev1.(*Request).Execute.func1()
          /go/src/github.com/Rookout/golib/vendor/gopkg.in/resty.v1/request.go:482 +0x1c4
      github.com/Rookout/golib/vendor/gopkg.in/resty%2ev1.Backoff()
          /go/src/github.com/Rookout/golib/vendor/gopkg.in/resty.v1/retry.go:85 +0x330
      github.com/Rookout/golib/vendor/gopkg.in/resty%2ev1.(*Request).Execute()
          /go/src/github.com/Rookout/golib/vendor/gopkg.in/resty.v1/request.go:476 +0x58c
      github.com/Rookout/golib/pkg/routes.(*CrudSession).executeInternal()
          /go/src/github.com/Rookout/golib/pkg/routes/crud_session.go:168 +0x47d
      github.com/Rookout/golib/pkg/routes.(*CrudSession).Execute()
          /go/src/github.com/Rookout/golib/pkg/routes/crud_session.go:175 +0xb8
      github.com/Rookout/golib/pkg/routes.(*CrudClient).Post()
          /go/src/github.com/Rookout/golib/pkg/routes/crud_client.go:42 +0x132
      github.com/Rookout/golib/pkg/control.(*Notifications).SendRookRuleStatus.func1()
          /go/src/github.com/Rookout/golib/pkg/control/notifications.go:172 +0x13c
    
    Goroutine 109 (finished) created at:
      net/http.http2bodyWriterState.scheduleBodyWrite()
          /usr/local/go/src/net/http/h2_bundle.go:9087 +0xb8
      net/http.(*http2ClientConn).roundTrip()
          /usr/local/go/src/net/http/h2_bundle.go:7626 +0x81b
      net/http.(*http2Transport).RoundTripOpt()
          /usr/local/go/src/net/http/h2_bundle.go:7037 +0x22d
      net/http.(*http2Transport).RoundTrip()
          /usr/local/go/src/net/http/h2_bundle.go:6999 +0x4b
      net/http.http2noDialH2RoundTripper.RoundTrip()
          /usr/local/go/src/net/http/h2_bundle.go:1019 +0x46
      net/http.(*Transport).roundTrip()
          /usr/local/go/src/net/http/transport.go:415 +0x1269
      net/http.(*Transport).RoundTrip()
          /usr/local/go/src/net/http/roundtrip.go:17 +0x42
      net/http.send()
          /usr/local/go/src/net/http/client.go:250 +0x304
      net/http.(*Client).send()
          /usr/local/go/src/net/http/client.go:174 +0x1ca
      net/http.(*Client).do()
          /usr/local/go/src/net/http/client.go:641 +0x53a
      net/http.(*Client).Do()
          /usr/local/go/src/net/http/client.go:509 +0x42
      github.com/Rookout/golib/vendor/gopkg.in/resty%2ev1.(*Client).execute()
          /go/src/github.com/Rookout/golib/vendor/gopkg.in/resty.v1/client.go:819 +0x3dd
      github.com/Rookout/golib/vendor/gopkg.in/resty%2ev1.(*Request).Execute.func1()
          /go/src/github.com/Rookout/golib/vendor/gopkg.in/resty.v1/request.go:482 +0x1c4
      github.com/Rookout/golib/vendor/gopkg.in/resty%2ev1.Backoff()
          /go/src/github.com/Rookout/golib/vendor/gopkg.in/resty.v1/retry.go:85 +0x330
      github.com/Rookout/golib/vendor/gopkg.in/resty%2ev1.(*Request).Execute()
          /go/src/github.com/Rookout/golib/vendor/gopkg.in/resty.v1/request.go:476 +0x58c
      github.com/Rookout/golib/pkg/routes.(*CrudSession).executeInternal()
          /go/src/github.com/Rookout/golib/pkg/routes/crud_session.go:168 +0x47d
      github.com/Rookout/golib/pkg/routes.(*CrudSession).Execute()
          /go/src/github.com/Rookout/golib/pkg/routes/crud_session.go:175 +0xb8
      github.com/Rookout/golib/pkg/routes.(*CrudClient).Post()
          /go/src/github.com/Rookout/golib/pkg/routes/crud_client.go:42 +0x132
      github.com/Rookout/golib/pkg/control.(*Notifications).SendRookRuleStatus.func1()
          /go/src/github.com/Rookout/golib/pkg/control/notifications.go:172 +0x13c
    ==================
    

    The code is not open source atm so I cannot show you exactly what wer'e doing but the main takeaways are:

    1. We share a single client across multiple go routines
    2. We create a new request struct for every request we execute (client.NewRequest())
    3. We use the retry feature Any idea what's the problem here? Is it a false positive or not?
      Thanks
    bug 
    opened by hedwigz 29
  • Verifying module, checksum mismatch (with new version 2.5.0)

    Verifying module, checksum mismatch (with new version 2.5.0)

    I'm getting this error after upgrading from resty 2.4.0 to 2.5.0:

    github.com/go-resty/resty/[email protected]: verifying module: checksum mismatch
            downloaded: h1:GmCjQ7qW3Dzr3Lh7FvTrRJSWgYNWswDdOy+T8sgTAFI=
            sum.golang.org: h1:WFb5bD49/85PO7WgAjZ+/TJQ+Ty1XOcWEfD1zIFCM1c=
    
    SECURITY ERROR
    This download does NOT match the one reported by the checksum server.
    The bits may have been replaced on the origin server, or an attacker may
    have intercepted the download attempt.
    
    For more information, see 'go help module-auth'.
    

    Already did:

    go clean -modcache
    go get -u ./... && go mod tidy
    

    Any ideas? Thanks!

    opened by mrz1836 28
  • Big file upload

    Big file upload

    Hi,

    i tried my luck with the other issues, sorry if this is a duplicate.

    Is it possible to upload files without loading the entire content into memory ?

    Cheers !

    enhancement 
    opened by lacravate 21
  • v2 Release error with go mod

    v2 Release error with go mod

    I have tried to make a release v2 with the following approach

    • Merging into master
    • Having v2 branch

    Not sure, what is missing? ran into an error. So reverted the master back to the previous state.

    May be go mod vs github.com/go-resty/resty vs gopkg.in/resty.v1 - Need an investigation!!

    go: finding github.com/go-resty/resty/v2 v2.0.0
    go: finding golang.org/x/net v0.0.0-20190619014844-b5b0513f8c1b
    go: finding golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2
    go: finding golang.org/x/text v0.3.0
    go: finding golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a
    go: finding github.com/go-resty/resty v1.12.0
    go: downloading github.com/go-resty/resty v1.12.0
    go: extracting github.com/go-resty/resty v1.12.0
    go: github.com/go-resty/[email protected]: parsing go.mod: unexpected module path "gopkg.in/resty.v1"
    go: error loading module requirements
    
    opened by jeevatkm 15
  • Resty v2 release plan and Create migration guide from v1 to v2

    Resty v2 release plan and Create migration guide from v1 to v2

    This issue is to provide v2 release plan and track the migration guide from v1.x to v2.x

    Release Plan:

    • Create a v1 branch from master branch
      • v1 branch will be kept for critical bug fixes only for 6 months, no enhancements and no feature additions
      • Any bug fixes will be ported to master branch to reflect on v2 series
      • v1 will be unsupported and locked down in 6 months from the date of v2 release
    • Make Release Candidates
      • Fix any issues arises
    • Merge v2 branch into the master branch
    • Make a v2.0.0 release from the master branch

    Release Candidates:

    v2.0.0-rc.1 is ready to try it out.

    # add it go.mod
    github.com/go-resty/resty v2.0.0-rc.1
    

    Migration Guide: (In-progress)

    v2 brings https://github.com/go-resty/resty/issues?q=is%3Aclosed+milestone%3A%22v2.0.0+Milestone%22

    documentation v2 
    opened by jeevatkm 15
  • DATA RACE in resty.(*Client).execute()

    DATA RACE in resty.(*Client).execute()

    Hello, I am use resty in multi-goroutine and case the DATA RACE

    test.go `package main

    import ( "github.com/go-resty/resty" "sync" )

    func main() { w := sync.WaitGroup{} for i := 0; i < 50; i++ { w.Add(1) go func() { defer w.Done() resty.R().Get("http://httpbin.org/get") }() } w.Wait() }go run -race test.go`

    bug 
    opened by iyidan 15
  • Support Error marshalling using application/problem+json content type

    Support Error marshalling using application/problem+json content type

    I just found out that Mailchimp uses this header which is unfortunate and unusual afaik but there is a spec: https://tools.ietf.org/html/rfc7807 that seems to define this.

    It would be nice to be able to use the SetError() functionality.

    enhancement 
    opened by dahankzter 14
  • How to set Content-Length header

    How to set Content-Length header

    I'm trying to call an API, that expects 'Content-Length' = 0 for a HTTP PATCH Request. There is no request body for this request.

    It seems golang (from 1.8) does not allow to set Content-length with zero bytes. ( pls see -- https://github.com/golang/go/issues/20257)

    How do I set the header? I have tried

    restyClient.SetBody(http.NoBody).SetContentLength(true)
    

    And

    reqHeader := map[string]string {
    		"Content-Length": "0",
    }
    

    None of these 2 ways set the content-length header.

    enhancement 
    opened by vijayrajah 13
  • why resty very slow

    why resty very slow

    Resty vs Curl

    • Resty vs Curl
    • Access Same URL

    Result

    Resty + fmt :

    time ./main
    real	0m11.247s
    user	0m0.045s
    sys	0m0.027s
    

    curl :

    time curl "sameurl"
    real	0m1.373s
    user	0m0.069s
    sys	0m0.020s
    

    Code

    package main
    
    import (
    	"fmt"
    )
    
    import (
    	"gopkg.in/resty.v1"
    )
    
    func main() {
    	resp, _ := resty.R().Get("https://someurl")
    	fmt.Println(resp)
    }
    
    support answered 
    opened by codenoid 13
  • my SetBody method doesn't work in Get request method

    my SetBody method doesn't work in Get request method

    response, err := client.R().
    		SetResult(&database.ItemOut{}).
    //setbody not working in GET
    		SetBody([]byte(`{"id":1}`)).
    		SetHeader("Content-Type", "application/json").
    //setbody not working in GET
    		Get(URL)
    
    

    Body is not sent

    opened by ruiborda 0
  • Feat: support set querystring from struct

    Feat: support set querystring from struct

    SetQueryStruct method set struct parameter and its value in the current request.

    For Example:

     type Options struct {
      	Query   string `url:"q"`
      	ShowAll bool   `url:"all"`
      	Page    int    `url:"page,omitempty"`
     }
     opt := Options{Query:"foo", ShowAll: true}
     client.R().
    	SetQueryStruct(opt)
    

    will output: "q=foo&all=true"

    opened by vlean 5
  • Change retry output to warn or debug

    Change retry output to warn or debug

    The code for output on a retry attempt is currently an error - it's debatable if it's actually an error or not. In my case, retry is pretty typical and only when all attempts have been tried is it an error.

    I propose that this code

    			resp, err = r.client.execute(r)
    			if err != nil {
    				r.client.log.Errorf("%v, Attempt %v", err, r.Attempt)
    			}
    

    Be changed to

    r.client.log.Warnf
    

    Or

    r.client.log.Debugf
    

    So that it can be suppressed unless there is an issue and that when all attempts are tried, then it outputs an Errorf

    If this is ok, I will make the change and submit a PR

    opened by chb0github 0
  • Allow SetOutput and SetResult to be used together

    Allow SetOutput and SetResult to be used together

    It seems SetOutput reads the entire stream then SetResult will error with unexpected end of JSON input

    Would be useful to allow these together.

    Use case:

    We use resty in end-to-end API tests and one pattern we use is dumping outputs of specific endpoints to files which can be used for frontend fixtures/examples for the frontend team. I like to keep test code simple so it would be awesome to be able to make these HTTP requests for tests concise using Resty:

    				r, err := cl.R().
    					SetHeader("Authorization", user.SeedUser_11_Account.AuthToken).
    					SetOutput(testhelpers.OutputPath(t, "api", path)("get.json")). // outputs the result of this test to a file
    					SetResult(&result). // also parse the response and store in a variable for test assertions
    					Get(path)
    				testhelpers.AssertResponseNoError(t, err, r)
    
    				assert.Equal(t, expected, result)
    
    opened by Southclaws 0
  • Fix multipart file readers not being reset when doing a retry

    Fix multipart file readers not being reset when doing a retry

    As mentioned in https://github.com/go-resty/resty/issues/166 by @neganovalexey, when doing a retry on a multipart request the io.Reader is not reset to the start again. This can lead to subtle bugs, as the request will be retried, but the form part of the file will be empty, because the reader was already exhausted. Solving this issue in the caller code is pretty ugly, because Request does not expose access to multipartFiles and so the caller would have to use RetryHooks and recreate the Response.Request and that at each call site (where there is access to the original ReadSeeker).

    In the PR, I created a new client options SetRetryResetReaders which adds a retry hook seeking the start of each reader in multipartFiles, if the reader it got also implements io.ReadSeeker. This solved the above issue described above for my usecase and should have minimal implications on existing usages.

    opened by nikplx 2
Releases(v2.7.0)
  • v2.7.0(Nov 4, 2021)

    Release Notes

    Enhancements

    • Added method SetHeaderMultiValues for easier adding of multi-value http headers #432 PR #452 @mhdiiilham
    • Updated Bazel build to work with 4.0.0 PR #428 @tanyabouman
    • Optimzed and improved the sync.Pool & Body Closure for json.NewEncoder buffers PR #421 @pborzenkov
    • Added RetryConditions to resty.Request #315, #324, #433, PR #436 @rohitkg98
    • Update go mod for dependencies PR #459 @jeevatkm
    • Added SetBaseURL and deprecated SetHostURL #441 PR #480 @jeevatkm
    • Made exported field on client.PathParams and request.PathParams PR #476 @lavoiesl
    • Adding ability to customize the XML marshal/unmarshal functions #481, PR #484 @jeevatkm

    Bug Fixes

    • Fixed: Empty file upload on multipart form, handling EOF from file readers #431 PR #438 @NathanBaulch
    • Fixed: SetScheme option side effects on schemeless Host URL #407 PR #460 @jeevatkm

    Tests

    • Add 1.16.x and remove 1.14.x from the Travis build PR #434 @kishaningithub
    • Migrated from Travis CI to Github Actions #479 PR #480 @jeevatkm
      • Thank you Travis CI for these many years of CI service to Resty project

    Documentation

    • Addressing broken members link in readme PR #435 @kishaningithub
    • Version update 2.6.0 on readme for go.mod PR #453 @cnmade
    Source code(tar.gz)
    Source code(zip)
  • v2.6.0(Apr 9, 2021)

    Release Notes

    Features

    • Added Retry hooks #416 PR #417 @Blokje5

    Enhancements

    • Added AddRetryAfterErrorCondition() option PR #384 @gtpaulose
    • Refactor(retry.sleepDuration): :recycle: extract jitterBackoff function PR #406 @ninedraft
    • Added a way set a Non-Canonical Header PR #413 @Lao-Tuo
    • Test case update When SetRetryCount -1, both resp and error are nil PR #392 @yjhmelody

    General

    • Addressing checksum issue on v2.5.0 with this release
    Source code(tar.gz)
    Source code(zip)
  • v2.5.0(Feb 11, 2021)

  • v2.4.0(Jan 11, 2021)

    Release Notes

    Features

    • Added a new OnError hook that is called when a Resty request returns an error PR #398 @justenwalker

    Enhancements

    • Preserve marshal errors in middleware request body handler #361, PR #362 @moorereason
    • Added go.sum to the project PR #375 @moorereason
    • Added Request Attempt and Remote IP Address in TraceInfo #352, #370, PR #374 @jeevatkm
    • Added HeaderAuthorizationKey in the Client struct, it can be configured #387 PR #403 @jeevatkm
    • Added SetPathParam method in Client snd Request for setting single path param #402 PR #403 @jeevatkm
    • Added option of http.NoBody when content length is set true and request body is nil #395 PR #403 @moorereason @jeevatkm

    Bug Fixes

    • Fixed - Trace timing issue when reused connections #346 PR #347 @moorereason
    • Fixed - Request, execute user defined middlewares after resty's internal middlewares PR #355 @lggomez
    • Fixed - Incorrect response time when saving the response file PR #357 @iwaltgen
    • Fixed - Set supplied argument value to the field PR #368 @lewisay
    • Fixed - Body size 0 when HTTP status code is 307, 308 #300 PR #380 @shiguangyin
    • Fixed - Travis Build issue, many PRs are waiting PR #366 @jeevatkm
    • Fixed - Retry sleep computation for 32bit arch PR #388 @creekorful

    Documentation

    • Added clarification on Request.RawRequest PR #354 @lggomez
    • Godoc update - typo correction PR #363 @Alex1996a
    • Corrected typo in AddRetryCondition function, readme example #365 PR #364 @ervitis
    • Added ForceContentType example PR #371 @mattfenwick
    • Added Resty package for Client and Response PR #378 @cxjava
    • Godoc update on Readme for retry condition func PR #390 @lambdalisue
    Source code(tar.gz)
    Source code(zip)
  • v2.3.0(May 21, 2020)

    Release Notes

    New Features

    • Add ability to set Authorization header Scheme #306, PR #307 @rigrassm

    Enhancements

    • Improving retry total value PR #322 @golemiso
    • Added force content type option for automatic unmarshalling #240, #276, PR #323 @jeevatkm
    • Make default retry not on middlewares errors PR #333 @lrita
    • Add SetMultipartFormData func to Request PR #337 @ArcticSnowman
    • Add types for middleware PR #341 @mloberg

    Bug Fixes

    • Addressing the issue of traceinfo totaltime #304, PR #321 @jeevatkm
    • Changes to show the right amount of time in Trace inf PR #331 @JoaquinJimenezGarcia
    • Fixed Debugf call in Request/Response logger PR #335 @phsym and @pierresy
    • Addressing nil pointer error while accessing cookie jar on user provided http client #330, PR #340 @jeevatkm
    • Addressing HTTP2 issue on go1.13 above #339, PR #340 @jeevatkm
    • Fix TraceInfo on failed connections #338, PR #342 @moorereason
    Source code(tar.gz)
    Source code(zip)
  • v2.3.0-rc.2(May 12, 2020)

  • v2.3.0-rc.1(May 11, 2020)

  • v2.2.0(Feb 24, 2020)

    Release Notes

    Enhancements

    • Added Request.Send() method to execute Request as-is PR #286 @dan-rising
    • Applied debugBodySizeLimit to Request debug logger PR #297 @viennadd
    • Added SetRootCertificateFromString method to read cert from string PR #313 @dzaytsev91

    Bug Fixes

    • Fixed - Trace context overrides request context if EnableTrace #285, PR #284 @xixinjie
    • Fixed - Failing first request and successfully retrying carries error from first #289, PR #290 @phillc
    • Fixed - Panic When Calling TraceInfo But Tracing Has Not Been Enabled #293, PR #296 @JonnyPillar

    Documentation

    • Added awesome go badge PR #280 @kishaningithub
    • Godoc and readme typo correction PR #310 @creekorful
    Source code(tar.gz)
    Source code(zip)
  • v2.1.0(Oct 10, 2019)

    Release Notes

    Enhancements

    • Added support for func http.Request.GetBody, so request body manipalation can be done via PreRequestHook (such as adding Content-MD5 entity-header, etc) #242 @jeevatkm
    • Added SetCookie and SetCookies method added into Request object #257 @jeevatkm
    • Updated default JSON request content-type value without charset per RFC e.g., application/json #258 @jeevatkm
    • Reducing memory allocation during debug log processing PR #277 @vivekv96
    • Code improvements @jeevatkm

    Bug Fixes

    • Fixed missing cookie values in the debug log from Cookie Jar #260, PR #261 @matthewpoer
    • Fixed Debug emits incorrect body when body contains % #270, PR #270 @kmanley
    Source code(tar.gz)
    Source code(zip)
  • v2.0.0(Jul 17, 2019)

    Release Notes

    How to use Resty v2?

    Please refer to README

    New Features

    • Dial a TCP connection from a specific Local Interface/IP Address #226 @jeevatkm
    • On-Demand Resty Request/Responce tracer, #216 @jeevatkm, see TraceInfo, see Client.EnableTrace and see Request.EnableTrace - idea born from @moorereason example gist
    • New RetryAfterFunc addition into Resty's retry capabilities PR #237 @neganovalexey, see RetryAfterFunc

    Enhancements

    • Build User-Agent string only once PR #221 @moorereason
    • Retry Backoff algorthim and follow enhancement PR #237 @neganovalexey
    • Log request and response debug log together for easy debugging, its highly helpful for parallel #218 @jeevatkm
    • Default values set while http.Transport creation simliar to Langauge default client #212 @jeevatkm
      • Timeout, KeepAlive, MaxIdleConns, IdleConnTimeout, TLSHandshakeTimeout, ExpectContinueTimeout, MaxIdleConnsPerHost
    • Added support to multipart/form-data payload without filename and content type values PR #236 @larryhu
    • Added HTTP verb PATCH into multipart support #239 @jeevatkm

    Breaking Changes - Migrating v1.x to v2

    • Resty v2 import path have changed to github.com/go-resty/resty #215 @jeevatkm
      • Resty v1 import path is not affected.
    • Resty Default Client approach have been removed. Create an instance of Resty client with appropriate settings for usage #232 @jeevatkm
    • PreRequestHook signature have been updated to func(cl *Client, r *http.Request) error #217 @jeevatkm
    • Retry condition function signature updated to RetryConditionFunc func(*Response, error) bool #237, #214 @neganovalexey, @jeevatkm
    • Resty v2 brings new Logger interface #229, refer to godoc @jeevatkm
    • Methods to accept type url.Values for Query string and Form data on Request struct #213 @jeevatkm
      • Refactored method from Request.SetMultiValueQueryParams to Request.SetQueryParamsFromValues
      • Refactored method from Request.SetMultiValueFormData to Request.SetFormDataFromValues
    Source code(tar.gz)
    Source code(zip)
  • v2.0.0-rc.4(Jul 16, 2019)

  • v2.0.0-rc.3(Jun 18, 2019)

  • v2.0.0-rc.2(Mar 28, 2019)

  • v2.0.0-rc.1(Mar 13, 2019)

  • v1.12.0(Feb 28, 2019)

  • v1.11.0(Jan 6, 2019)

    Changelog

    Enhancements

    • Add Content-Type application/json-rpc into Auto Unmarshaling support #203 @jeevatkm
    • Add Context() method into Request and consider logging prerequesthook updates in the debug log #206 @jeevatkm
    Source code(tar.gz)
    Source code(zip)
  • v1.10.3(Dec 5, 2018)

  • v1.10.2(Nov 9, 2018)

  • v1.10.1(Oct 28, 2018)

  • v1.10.0(Oct 22, 2018)

    Changelog

    Enhancement

    • Debug log callback added to customize log info before logging it #180 #182 PR #186 @jeevatkm
    • Updated every reference to point to gopkg.in/resty.v1 inline with go mod for v1 #193 @jeevatkm
    • Added path params value escape #184 PR #185 @jeevatkm

    Bug fix

    • Fixed - Accept-Encoding: gzip with Content-Length: -1 and Chunked response not decoded #187 PR #189 @visualphoenix
    Source code(tar.gz)
    Source code(zip)
  • v1.9.1(Aug 30, 2018)

  • v1.9.0(Aug 25, 2018)

    Changelog

    Enhancement

    • Added application/hal+json content type support PR #171 #172 @kmanley
    • Made IsJSONType and IsXMLType method more robust PR #174 @moorereason
    • Added opt-in method SetJSONEscapeHTML at client and request level to disable HTML escape on JSON payload request #177 #179 @jeevatkm

    Bug fix

    • Updated default user agent string format #176 #175 @jeevatkm
    • Go module fix, updated go.mod with import path gopkg.in/resty.v1 #178 @jeevatkm
    Source code(tar.gz)
    Source code(zip)
  • v1.8.0(Aug 5, 2018)

    Changelog

    • Update bazel definitions to work with release 0.13.0 PR #168 @paradoxengine
    • Added helper methods Response.IsSuccess() and Response.IsError() #169 @jeevatkm
    Source code(tar.gz)
    Source code(zip)
  • v1.7.0(Jul 4, 2018)

    Changelog

    Feature

    • Added built-in support for Host value override in the request #155, PR #156 @sorribas

    Bug fixes

    • Preserved URL input value in Path parameters #160 @jeevatkm
    • Addressing gzip error on Content-Length zero and Content-Encoding is gzip #164, PR #165 @Jack47
    Source code(tar.gz)
    Source code(zip)
  • v1.6(May 29, 2018)

  • v1.5(May 6, 2018)

    Changelog

    Enhancements

    • Added fallback gzip response handling #142 @jeevatkm
    • Added support for Bazel build PR #141 @paradoxengine
    • Test cases improvements PR #143 @moorereason
    • Code enhancement PR #145 and travis config PR #144 @moorereason

    Bug fix

    • Addressed transport override issue #146 @jeevatkm
    Source code(tar.gz)
    Source code(zip)
  • v1.4(Apr 5, 2018)

    Changelog

    Enhancements

    • Added support for RFC7807 - application/problem+json and application/problem+xml #134, #135 @jeevatkm
    • Bufferless large file on body R().SetBody(reader) #133, #136 @jeevatkm
    Source code(tar.gz)
    Source code(zip)
  • v1.3(Mar 2, 2018)

    Changelog:

    Enhancements:

    • Custom content type and data for multipart request PR #129 @Asker80
    • Debug log with concatenated string PR #128 @sudo-suhas
    • Allow uncommon HTTP methods to support payloads PR #122 @arun251
    • improved override header handling #125 @jeevatkm
    • Preserve query string order partially #124 @jeevatkm

    Bug Fix:

    • Missing query params on relative path request #131 @jeevatkm
    Source code(tar.gz)
    Source code(zip)
  • v1.2(Jan 26, 2018)

  • v1.1(Jan 25, 2018)

    Changelog

    Features

    • Added Request URL Path Params #103 @jeevatkm

    Enhancements

    • Auto detects file content type in mutlipart/form-data mode #109, PR #111 @gh0st42
    • Limit body size for debug log PR #99 @sudo-suhas
    • Log prefix enhancement #113 @jeevatkm
    • More friendly with mocking test libraries
    Source code(tar.gz)
    Source code(zip)
Owner
Go Resty
Simple HTTP and REST client library for Go
Go Resty
An idiomatic Go REST API starter kit (boilerplate) following the SOLID principles and Clean Architecture

Go RESTful API Starter Kit (Boilerplate) This starter kit is designed to get you up and running with a project structure optimized for developing REST

Qiang Xue 907 Jun 22, 2022
package for building REST-style Web Services using Go

go-restful package for building REST-style Web Services using Google Go Code examples using v3 REST asks developers to use HTTP methods explicitly and

Ernest Micklei 4.5k Jun 30, 2022
🍐 Elegant Golang REST API Framework

An Elegant Golang Web Framework Goyave is a progressive and accessible web application framework focused on REST APIs, aimed at making backend develop

SystemGlitch 1.1k Jun 23, 2022
A lightweight and fast http router from outer space

Alien Alien is a lightweight http router( multiplexer) for Go( Golang ), made for humans who don't like magic. Documentation docs Features fast ( see

Geofrey Ernest 123 May 27, 2022
Gin is a HTTP web framework written in Go (Golang). It features a Martini-like API with much better performance -- up to 40 times faster. If you need smashing performance, get yourself some Gin.

Gin Web Framework Gin is a web framework written in Go (Golang). It features a martini-like API with performance that is up to 40 times faster thanks

Gin-Gonic 60.5k Jun 27, 2022
Go http middleware handler for request coalescing

HTTP Coala NOTE: a new and improved implementation is available at https://github.com/go-chi/stampede Just a little bit of performance enhancing middl

go-chi 128 Apr 3, 2022
A high performance HTTP request router that scales well

HttpRouter HttpRouter is a lightweight high performance HTTP request router (also called multiplexer or just mux for short) for Go. In contrast to the

Julien Schmidt 14.2k Jun 22, 2022
Idiomatic HTTP Middleware for Golang

Negroni Notice: This is the library formerly known as github.com/codegangsta/negroni -- Github will automatically redirect requests to this repository

null 7.2k Jun 24, 2022
Go HTTP router

violetear Go HTTP router http://violetear.org Design Goals Keep it simple and small, avoiding extra complexity at all cost. KISS Support for static an

Nicolas Embriz 105 Mar 21, 2022
Flamingo Framework and Core Library. Flamingo is a go based framework for pluggable web projects. It is used to build scalable and maintainable (web)applications.

Flamingo Framework Flamingo is a web framework based on Go. It is designed to build pluggable and maintainable web projects. It is production ready, f

Flamingo 303 Jun 23, 2022
A simple blog framework built with GO. Uses HTML files and a JSON dict to give you more control over your content.

Go-Blog A simple template based blog framework. Instructions Built for GO version: 1 See the Documentation or Getting Started pages in the wiki. Notes

Matt West 45 Feb 18, 2022
Thespian is a library supporting use of the actor model in Go code.

Thespian is a library supporting use of the actor model in Go code.

Dustin J. Mitchell 1 Nov 24, 2021
Dead simple rate limit middleware for Go.

Limiter Dead simple rate limit middleware for Go. Simple API "Store" approach for backend Redis support (but not tied too) Middlewares: HTTP, FastHTTP

Ulule 1.6k Jun 22, 2022
Simple web framework for go, still quite beta at this point

WFDR Framework - Beta Release New 18/Feb/2012: Updated for go 1.0, new directory layout to take advantage of the go build tool. Background There's a m

null 23 Feb 11, 2021
Simple Contributors Report For Git

git-contrib Creates simple contributors report for git. Useful for different bra

Erman İmer 1 Apr 18, 2022
:link: Generate HTML and CSS together, on the fly

On The Fly Package for generating HTML and CSS together, on the fly. Can also be used for generating HTML, XML or CSS (or templates). HTML and CSS can

Alexander F. Rødseth 42 Apr 21, 2022
Fast and Reliable Golang Web Framework

Gramework The Good Framework Gramework long-term testing stand metrics screenshot made with Gramework Stats Dashboard and metrics middleware What is i

null 368 Jun 11, 2022
Mango is a modular web-application framework for Go, inspired by Rack, and PEP333.

Mango Mango is a modular web-application framework for Go, inspired by Rack and PEP333. Note: Not actively maintained. Overview Mango is most of all a

Paul Bellamy 366 Jun 3, 2022
This is only a mirror and Moved to https://gitea.com/lunny/tango

Tango 简体中文 Package tango is a micro & pluggable web framework for Go. Current version: v0.5.0 Version History Getting Started To install Tango: go get

Lunny Xiao 835 May 31, 2022