• Home
  • History
  • Annotate
Name Date Size #Lines LOC

..26-Oct-2021-

.gitignoreH A D26-Oct-2021333 3123

.travis.ymlH A D26-Oct-2021349 2215

BUILD.bazelH A D26-Oct-2021888 3732

LICENSEH A D26-Oct-20211.1 KiB2217

README.mdH A D26-Oct-202132.1 KiB888695

WORKSPACEH A D26-Oct-2021527 2820

client.goH A D26-Oct-202134.1 KiB1,088560

go.modH A D26-Oct-2021106 63

go.sumH A D26-Oct-2021718 87

middleware.goH A D26-Oct-202113.4 KiB546403

redirect.goH A D26-Oct-20213.5 KiB10262

request.goH A D26-Oct-202127.7 KiB865416

response.goH A D26-Oct-20215.1 KiB176113

resty.goH A D26-Oct-20211.1 KiB4124

retry.goH A D26-Oct-20215 KiB216155

trace.goH A D26-Oct-20214.1 KiB13174

transport.goH A D26-Oct-2021867 3627

transport112.goH A D26-Oct-2021837 3526

util.goH A D26-Oct-20218.9 KiB358269

README.md

1<p align="center">
2<h1 align="center">Resty</h1>
3<p align="center">Simple HTTP and REST client library for Go (inspired by Ruby rest-client)</p>
4<p align="center"><a href="#features">Features</a> section describes in detail about Resty capabilities</p>
5</p>
6<p align="center">
7<p align="center"><a href="https://travis-ci.org/go-resty/resty"><img src="https://travis-ci.org/go-resty/resty.svg?branch=master" alt="Build Status"></a> <a href="https://codecov.io/gh/go-resty/resty/branch/master"><img src="https://codecov.io/gh/go-resty/resty/branch/master/graph/badge.svg" alt="Code Coverage"></a> <a href="https://goreportcard.com/report/go-resty/resty"><img src="https://goreportcard.com/badge/go-resty/resty" alt="Go Report Card"></a> <a href="https://github.com/go-resty/resty/releases/latest"><img src="https://img.shields.io/badge/version-2.6.0-blue.svg" alt="Release Version"></a> <a href="https://pkg.go.dev/github.com/go-resty/resty/v2"><img src="https://pkg.go.dev/badge/github.com/go-resty/resty" alt="GoDoc"></a> <a href="LICENSE"><img src="https://img.shields.io/github/license/go-resty/resty.svg" alt="License"></a> <a href="https://github.com/avelino/awesome-go"><img src="https://awesome.re/mentioned-badge.svg" alt="Mentioned in Awesome Go"></a></p>
8</p>
9<p align="center">
10<h4 align="center">Resty Communication Channels</h4>
11<p align="center"><a href="https://gitter.im/go_resty/community?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge"><img src="https://badges.gitter.im/go_resty/community.svg" alt="Chat on Gitter - Resty Community"></a> <a href="https://twitter.com/go_resty"><img src="https://img.shields.io/badge/twitter-@go__resty-55acee.svg" alt="Twitter @go_resty"></a></p>
12</p>
13
14## News
15
16  * v2.6.0 [released](https://github.com/go-resty/resty/releases/tag/v2.6.0) and tagged on Apr 09, 2021.
17  * v2.0.0 [released](https://github.com/go-resty/resty/releases/tag/v2.0.0) and tagged on Jul 16, 2019.
18  * v1.12.0 [released](https://github.com/go-resty/resty/releases/tag/v1.12.0) and tagged on Feb 27, 2019.
19  * 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](https://github.com/go-resty/resty/graphs/contributors).
20
21## Features
22
23  * GET, POST, PUT, DELETE, HEAD, PATCH, OPTIONS, etc.
24  * Simple and chainable methods for settings and request
25  * [Request](https://pkg.go.dev/github.com/go-resty/resty/v2#Request) Body can be `string`, `[]byte`, `struct`, `map`, `slice` and `io.Reader` too
26    * Auto detects `Content-Type`
27    * Buffer less processing for `io.Reader`
28    * Native `*http.Request` instance may be accessed during middleware and request execution via `Request.RawRequest`
29    * Request Body can be read multiple times via `Request.RawRequest.GetBody()`
30  * [Response](https://pkg.go.dev/github.com/go-resty/resty/v2#Response) object gives you more possibility
31    * Access as `[]byte` array - `response.Body()` OR Access as `string` - `response.String()`
32    * Know your `response.Time()` and when we `response.ReceivedAt()`
33  * Automatic marshal and unmarshal for `JSON` and `XML` content type
34    * Default is `JSON`, if you supply `struct/map` without header `Content-Type`
35    * For auto-unmarshal, refer to -
36        - Success scenario [Request.SetResult()](https://pkg.go.dev/github.com/go-resty/resty/v2#Request.SetResult) and [Response.Result()](https://pkg.go.dev/github.com/go-resty/resty/v2#Response.Result).
37        - Error scenario [Request.SetError()](https://pkg.go.dev/github.com/go-resty/resty/v2#Request.SetError) and [Response.Error()](https://pkg.go.dev/github.com/go-resty/resty/v2#Response.Error).
38        - Supports [RFC7807](https://tools.ietf.org/html/rfc7807) - `application/problem+json` & `application/problem+xml`
39  * Easy to upload one or more file(s) via `multipart/form-data`
40    * Auto detects file content type
41  * Request URL [Path Params (aka URI Params)](https://pkg.go.dev/github.com/go-resty/resty/v2#Request.SetPathParams)
42  * Backoff Retry Mechanism with retry condition function [reference](retry_test.go)
43  * Resty client HTTP & REST [Request](https://pkg.go.dev/github.com/go-resty/resty/v2#Client.OnBeforeRequest) and [Response](https://pkg.go.dev/github.com/go-resty/resty/v2#Client.OnAfterResponse) middlewares
44  * `Request.SetContext` supported
45  * Authorization option of `BasicAuth` and `Bearer` token
46  * Set request `ContentLength` value for all request or particular request
47  * Custom [Root Certificates](https://pkg.go.dev/github.com/go-resty/resty/v2#Client.SetRootCertificate) and Client [Certificates](https://pkg.go.dev/github.com/go-resty/resty/v2#Client.SetCertificates)
48  * Download/Save HTTP response directly into File, like `curl -o` flag. See [SetOutputDirectory](https://pkg.go.dev/github.com/go-resty/resty/v2#Client.SetOutputDirectory) & [SetOutput](https://pkg.go.dev/github.com/go-resty/resty/v2#Request.SetOutput).
49  * Cookies for your request and CookieJar support
50  * SRV Record based request instead of Host URL
51  * Client settings like `Timeout`, `RedirectPolicy`, `Proxy`, `TLSClientConfig`, `Transport`, etc.
52  * Optionally allows GET request with payload, see [SetAllowGetMethodPayload](https://pkg.go.dev/github.com/go-resty/resty/v2#Client.SetAllowGetMethodPayload)
53  * Supports registering external JSON library into resty, see [how to use](https://github.com/go-resty/resty/issues/76#issuecomment-314015250)
54  * Exposes Response reader without reading response (no auto-unmarshaling) if need be, see [how to use](https://github.com/go-resty/resty/issues/87#issuecomment-322100604)
55  * Option to specify expected `Content-Type` when response `Content-Type` header missing. Refer to [#92](https://github.com/go-resty/resty/issues/92)
56  * Resty design
57    * Have client level settings & options and also override at Request level if you want to
58    * Request and Response middleware
59    * Create Multiple clients if you want to `resty.New()`
60    * Supports `http.RoundTripper` implementation, see [SetTransport](https://pkg.go.dev/github.com/go-resty/resty/v2#Client.SetTransport)
61    * goroutine concurrent safe
62    * Resty Client trace, see [Client.EnableTrace](https://pkg.go.dev/github.com/go-resty/resty/v2#Client.EnableTrace) and [Request.EnableTrace](https://pkg.go.dev/github.com/go-resty/resty/v2#Request.EnableTrace)
63      * Since v2.4.0, trace info contains a `RequestAttempt` value, and the `Request` object contains an `Attempt` attribute
64    * Debug mode - clean and informative logging presentation
65    * Gzip - Go does it automatically also resty has fallback handling too
66    * Works fine with `HTTP/2` and `HTTP/1.1`
67  * [Bazel support](#bazel-support)
68  * Easily mock Resty for testing, [for e.g.](#mocking-http-requests-using-httpmock-library)
69  * Well tested client library
70
71### Included Batteries
72
73  * Redirect Policies - see [how to use](#redirect-policy)
74    * NoRedirectPolicy
75    * FlexibleRedirectPolicy
76    * DomainCheckRedirectPolicy
77    * etc. [more info](redirect.go)
78  * Retry Mechanism [how to use](#retries)
79    * Backoff Retry
80    * Conditional Retry
81    * Since v2.6.0, Retry Hooks - [Client](https://pkg.go.dev/github.com/go-resty/resty/v2#Client.AddRetryHook), [Request](https://pkg.go.dev/github.com/go-resty/resty/v2#Request.AddRetryHook)
82  * SRV Record based request instead of Host URL [how to use](resty_test.go#L1412)
83  * etc (upcoming - throw your idea's [here](https://github.com/go-resty/resty/issues)).
84
85
86#### Supported Go Versions
87
88Initially Resty started supporting `go modules` since `v1.10.0` release.
89
90Starting Resty v2 and higher versions, it fully embraces [go modules](https://github.com/golang/go/wiki/Modules) package release. It requires a Go version capable of understanding `/vN` suffixed imports:
91
92- 1.9.7+
93- 1.10.3+
94- 1.11+
95
96
97## It might be beneficial for your project :smile:
98
99Resty author also published following projects for Go Community.
100
101  * [aah framework](https://aahframework.org) - A secure, flexible, rapid Go web framework.
102  * [THUMBAI](https://thumbai.app) - Go Mod Repository, Go Vanity Service and Simple Proxy Server.
103  * [go-model](https://github.com/jeevatkm/go-model) - Robust & Easy to use model mapper and utility methods for Go `struct`.
104
105
106## Installation
107
108```bash
109# Go Modules
110require github.com/go-resty/resty/v2 v2.4.0
111```
112
113## Usage
114
115The following samples will assist you to become as comfortable as possible with resty library.
116
117```go
118// Import resty into your code and refer it as `resty`.
119import "github.com/go-resty/resty/v2"
120```
121
122#### Simple GET
123
124```go
125// Create a Resty Client
126client := resty.New()
127
128resp, err := client.R().
129    EnableTrace().
130    Get("https://httpbin.org/get")
131
132// Explore response object
133fmt.Println("Response Info:")
134fmt.Println("  Error      :", err)
135fmt.Println("  Status Code:", resp.StatusCode())
136fmt.Println("  Status     :", resp.Status())
137fmt.Println("  Proto      :", resp.Proto())
138fmt.Println("  Time       :", resp.Time())
139fmt.Println("  Received At:", resp.ReceivedAt())
140fmt.Println("  Body       :\n", resp)
141fmt.Println()
142
143// Explore trace info
144fmt.Println("Request Trace Info:")
145ti := resp.Request.TraceInfo()
146fmt.Println("  DNSLookup     :", ti.DNSLookup)
147fmt.Println("  ConnTime      :", ti.ConnTime)
148fmt.Println("  TCPConnTime   :", ti.TCPConnTime)
149fmt.Println("  TLSHandshake  :", ti.TLSHandshake)
150fmt.Println("  ServerTime    :", ti.ServerTime)
151fmt.Println("  ResponseTime  :", ti.ResponseTime)
152fmt.Println("  TotalTime     :", ti.TotalTime)
153fmt.Println("  IsConnReused  :", ti.IsConnReused)
154fmt.Println("  IsConnWasIdle :", ti.IsConnWasIdle)
155fmt.Println("  ConnIdleTime  :", ti.ConnIdleTime)
156fmt.Println("  RequestAttempt:", ti.RequestAttempt)
157fmt.Println("  RemoteAddr    :", ti.RemoteAddr.String())
158
159/* Output
160Response Info:
161  Error      : <nil>
162  Status Code: 200
163  Status     : 200 OK
164  Proto      : HTTP/2.0
165  Time       : 457.034718ms
166  Received At: 2020-09-14 15:35:29.784681 -0700 PDT m=+0.458137045
167  Body       :
168  {
169    "args": {},
170    "headers": {
171      "Accept-Encoding": "gzip",
172      "Host": "httpbin.org",
173      "User-Agent": "go-resty/2.4.0 (https://github.com/go-resty/resty)",
174      "X-Amzn-Trace-Id": "Root=1-5f5ff031-000ff6292204aa6898e4de49"
175    },
176    "origin": "0.0.0.0",
177    "url": "https://httpbin.org/get"
178  }
179
180Request Trace Info:
181  DNSLookup     : 4.074657ms
182  ConnTime      : 381.709936ms
183  TCPConnTime   : 77.428048ms
184  TLSHandshake  : 299.623597ms
185  ServerTime    : 75.414703ms
186  ResponseTime  : 79.337µs
187  TotalTime     : 457.034718ms
188  IsConnReused  : false
189  IsConnWasIdle : false
190  ConnIdleTime  : 0s
191  RequestAttempt: 1
192  RemoteAddr    : 3.221.81.55:443
193*/
194```
195
196#### Enhanced GET
197
198```go
199// Create a Resty Client
200client := resty.New()
201
202resp, err := client.R().
203      SetQueryParams(map[string]string{
204          "page_no": "1",
205          "limit": "20",
206          "sort":"name",
207          "order": "asc",
208          "random":strconv.FormatInt(time.Now().Unix(), 10),
209      }).
210      SetHeader("Accept", "application/json").
211      SetAuthToken("BC594900518B4F7EAC75BD37F019E08FBC594900518B4F7EAC75BD37F019E08F").
212      Get("/search_result")
213
214
215// Sample of using Request.SetQueryString method
216resp, err := client.R().
217      SetQueryString("productId=232&template=fresh-sample&cat=resty&source=google&kw=buy a lot more").
218      SetHeader("Accept", "application/json").
219      SetAuthToken("BC594900518B4F7EAC75BD37F019E08FBC594900518B4F7EAC75BD37F019E08F").
220      Get("/show_product")
221
222
223// If necessary, you can force response content type to tell Resty to parse a JSON response into your struct
224resp, err := client.R().
225      SetResult(result).
226      ForceContentType("application/json").
227      Get("v2/alpine/manifests/latest")
228```
229
230#### Various POST method combinations
231
232```go
233// Create a Resty Client
234client := resty.New()
235
236// POST JSON string
237// No need to set content type, if you have client level setting
238resp, err := client.R().
239      SetHeader("Content-Type", "application/json").
240      SetBody(`{"username":"testuser", "password":"testpass"}`).
241      SetResult(&AuthSuccess{}).    // or SetResult(AuthSuccess{}).
242      Post("https://myapp.com/login")
243
244// POST []byte array
245// No need to set content type, if you have client level setting
246resp, err := client.R().
247      SetHeader("Content-Type", "application/json").
248      SetBody([]byte(`{"username":"testuser", "password":"testpass"}`)).
249      SetResult(&AuthSuccess{}).    // or SetResult(AuthSuccess{}).
250      Post("https://myapp.com/login")
251
252// POST Struct, default is JSON content type. No need to set one
253resp, err := client.R().
254      SetBody(User{Username: "testuser", Password: "testpass"}).
255      SetResult(&AuthSuccess{}).    // or SetResult(AuthSuccess{}).
256      SetError(&AuthError{}).       // or SetError(AuthError{}).
257      Post("https://myapp.com/login")
258
259// POST Map, default is JSON content type. No need to set one
260resp, err := client.R().
261      SetBody(map[string]interface{}{"username": "testuser", "password": "testpass"}).
262      SetResult(&AuthSuccess{}).    // or SetResult(AuthSuccess{}).
263      SetError(&AuthError{}).       // or SetError(AuthError{}).
264      Post("https://myapp.com/login")
265
266// POST of raw bytes for file upload. For example: upload file to Dropbox
267fileBytes, _ := ioutil.ReadFile("/Users/jeeva/mydocument.pdf")
268
269// See we are not setting content-type header, since go-resty automatically detects Content-Type for you
270resp, err := client.R().
271      SetBody(fileBytes).
272      SetContentLength(true).          // Dropbox expects this value
273      SetAuthToken("<your-auth-token>").
274      SetError(&DropboxError{}).       // or SetError(DropboxError{}).
275      Post("https://content.dropboxapi.com/1/files_put/auto/resty/mydocument.pdf") // for upload Dropbox supports PUT too
276
277// Note: resty detects Content-Type for request body/payload if content type header is not set.
278//   * For struct and map data type defaults to 'application/json'
279//   * Fallback is plain text content type
280```
281
282#### Sample PUT
283
284You can use various combinations of `PUT` method call like demonstrated for `POST`.
285
286```go
287// Note: This is one sample of PUT method usage, refer POST for more combination
288
289// Create a Resty Client
290client := resty.New()
291
292// Request goes as JSON content type
293// No need to set auth token, error, if you have client level settings
294resp, err := client.R().
295      SetBody(Article{
296        Title: "go-resty",
297        Content: "This is my article content, oh ya!",
298        Author: "Jeevanandam M",
299        Tags: []string{"article", "sample", "resty"},
300      }).
301      SetAuthToken("C6A79608-782F-4ED0-A11D-BD82FAD829CD").
302      SetError(&Error{}).       // or SetError(Error{}).
303      Put("https://myapp.com/article/1234")
304```
305
306#### Sample PATCH
307
308You can use various combinations of `PATCH` method call like demonstrated for `POST`.
309
310```go
311// Note: This is one sample of PUT method usage, refer POST for more combination
312
313// Create a Resty Client
314client := resty.New()
315
316// Request goes as JSON content type
317// No need to set auth token, error, if you have client level settings
318resp, err := client.R().
319      SetBody(Article{
320        Tags: []string{"new tag1", "new tag2"},
321      }).
322      SetAuthToken("C6A79608-782F-4ED0-A11D-BD82FAD829CD").
323      SetError(&Error{}).       // or SetError(Error{}).
324      Patch("https://myapp.com/articles/1234")
325```
326
327#### Sample DELETE, HEAD, OPTIONS
328
329```go
330// Create a Resty Client
331client := resty.New()
332
333// DELETE a article
334// No need to set auth token, error, if you have client level settings
335resp, err := client.R().
336      SetAuthToken("C6A79608-782F-4ED0-A11D-BD82FAD829CD").
337      SetError(&Error{}).       // or SetError(Error{}).
338      Delete("https://myapp.com/articles/1234")
339
340// DELETE a articles with payload/body as a JSON string
341// No need to set auth token, error, if you have client level settings
342resp, err := client.R().
343      SetAuthToken("C6A79608-782F-4ED0-A11D-BD82FAD829CD").
344      SetError(&Error{}).       // or SetError(Error{}).
345      SetHeader("Content-Type", "application/json").
346      SetBody(`{article_ids: [1002, 1006, 1007, 87683, 45432] }`).
347      Delete("https://myapp.com/articles")
348
349// HEAD of resource
350// No need to set auth token, if you have client level settings
351resp, err := client.R().
352      SetAuthToken("C6A79608-782F-4ED0-A11D-BD82FAD829CD").
353      Head("https://myapp.com/videos/hi-res-video")
354
355// OPTIONS of resource
356// No need to set auth token, if you have client level settings
357resp, err := client.R().
358      SetAuthToken("C6A79608-782F-4ED0-A11D-BD82FAD829CD").
359      Options("https://myapp.com/servers/nyc-dc-01")
360```
361
362### Multipart File(s) upload
363
364#### Using io.Reader
365
366```go
367profileImgBytes, _ := ioutil.ReadFile("/Users/jeeva/test-img.png")
368notesBytes, _ := ioutil.ReadFile("/Users/jeeva/text-file.txt")
369
370// Create a Resty Client
371client := resty.New()
372
373resp, err := client.R().
374      SetFileReader("profile_img", "test-img.png", bytes.NewReader(profileImgBytes)).
375      SetFileReader("notes", "text-file.txt", bytes.NewReader(notesBytes)).
376      SetFormData(map[string]string{
377          "first_name": "Jeevanandam",
378          "last_name": "M",
379      }).
380      Post("http://myapp.com/upload")
381```
382
383#### Using File directly from Path
384
385```go
386// Create a Resty Client
387client := resty.New()
388
389// Single file scenario
390resp, err := client.R().
391      SetFile("profile_img", "/Users/jeeva/test-img.png").
392      Post("http://myapp.com/upload")
393
394// Multiple files scenario
395resp, err := client.R().
396      SetFiles(map[string]string{
397        "profile_img": "/Users/jeeva/test-img.png",
398        "notes": "/Users/jeeva/text-file.txt",
399      }).
400      Post("http://myapp.com/upload")
401
402// Multipart of form fields and files
403resp, err := client.R().
404      SetFiles(map[string]string{
405        "profile_img": "/Users/jeeva/test-img.png",
406        "notes": "/Users/jeeva/text-file.txt",
407      }).
408      SetFormData(map[string]string{
409        "first_name": "Jeevanandam",
410        "last_name": "M",
411        "zip_code": "00001",
412        "city": "my city",
413        "access_token": "C6A79608-782F-4ED0-A11D-BD82FAD829CD",
414      }).
415      Post("http://myapp.com/profile")
416```
417
418#### Sample Form submission
419
420```go
421// Create a Resty Client
422client := resty.New()
423
424// just mentioning about POST as an example with simple flow
425// User Login
426resp, err := client.R().
427      SetFormData(map[string]string{
428        "username": "jeeva",
429        "password": "mypass",
430      }).
431      Post("http://myapp.com/login")
432
433// Followed by profile update
434resp, err := client.R().
435      SetFormData(map[string]string{
436        "first_name": "Jeevanandam",
437        "last_name": "M",
438        "zip_code": "00001",
439        "city": "new city update",
440      }).
441      Post("http://myapp.com/profile")
442
443// Multi value form data
444criteria := url.Values{
445  "search_criteria": []string{"book", "glass", "pencil"},
446}
447resp, err := client.R().
448      SetFormDataFromValues(criteria).
449      Post("http://myapp.com/search")
450```
451
452#### Save HTTP Response into File
453
454```go
455// Create a Resty Client
456client := resty.New()
457
458// Setting output directory path, If directory not exists then resty creates one!
459// This is optional one, if you're planning using absoule path in
460// `Request.SetOutput` and can used together.
461client.SetOutputDirectory("/Users/jeeva/Downloads")
462
463// HTTP response gets saved into file, similar to curl -o flag
464_, err := client.R().
465          SetOutput("plugin/ReplyWithHeader-v5.1-beta.zip").
466          Get("http://bit.ly/1LouEKr")
467
468// OR using absolute path
469// Note: output directory path is not used for absolute path
470_, err := client.R().
471          SetOutput("/MyDownloads/plugin/ReplyWithHeader-v5.1-beta.zip").
472          Get("http://bit.ly/1LouEKr")
473```
474
475#### Request URL Path Params
476
477Resty 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.
478
479```go
480// Create a Resty Client
481client := resty.New()
482
483client.R().SetPathParams(map[string]string{
484   "userId": "sample@sample.com",
485   "subAccountId": "100002",
486}).
487Get("/v1/users/{userId}/{subAccountId}/details")
488
489// Result:
490//   Composed URL - /v1/users/sample@sample.com/100002/details
491```
492
493#### Request and Response Middleware
494
495Resty provides middleware ability to manipulate for Request and Response. It is more flexible than callback approach.
496
497```go
498// Create a Resty Client
499client := resty.New()
500
501// Registering Request Middleware
502client.OnBeforeRequest(func(c *resty.Client, req *resty.Request) error {
503    // Now you have access to Client and current Request object
504    // manipulate it as per your need
505
506    return nil  // if its success otherwise return error
507  })
508
509// Registering Response Middleware
510client.OnAfterResponse(func(c *resty.Client, resp *resty.Response) error {
511    // Now you have access to Client and current Response object
512    // manipulate it as per your need
513
514    return nil  // if its success otherwise return error
515  })
516```
517
518#### OnError Hooks
519
520Resty provides OnError hooks that may be called because:
521
522- The client failed to send the request due to connection timeout, TLS handshake failure, etc...
523- The request was retried the maximum amount of times, and still failed.
524
525If there was a response from the server, the original error will be wrapped in `*resty.ResponseError` which contains the last response received.
526
527```go
528// Create a Resty Client
529client := resty.New()
530
531client.OnError(func(req *resty.Request, err error) {
532  if v, ok := err.(*resty.ResponseError); ok {
533    // v.Response contains the last response from the server
534    // v.Err contains the original error
535  }
536  // Log the error, increment a metric, etc...
537})
538```
539
540#### Redirect Policy
541
542Resty provides few ready to use redirect policy(s) also it supports multiple policies together.
543
544```go
545// Create a Resty Client
546client := resty.New()
547
548// Assign Client Redirect Policy. Create one as per you need
549client.SetRedirectPolicy(resty.FlexibleRedirectPolicy(15))
550
551// Wanna multiple policies such as redirect count, domain name check, etc
552client.SetRedirectPolicy(resty.FlexibleRedirectPolicy(20),
553                        resty.DomainCheckRedirectPolicy("host1.com", "host2.org", "host3.net"))
554```
555
556##### Custom Redirect Policy
557
558Implement [RedirectPolicy](redirect.go#L20) interface and register it with resty client. Have a look [redirect.go](redirect.go) for more information.
559
560```go
561// Create a Resty Client
562client := resty.New()
563
564// Using raw func into resty.SetRedirectPolicy
565client.SetRedirectPolicy(resty.RedirectPolicyFunc(func(req *http.Request, via []*http.Request) error {
566  // Implement your logic here
567
568  // return nil for continue redirect otherwise return error to stop/prevent redirect
569  return nil
570}))
571
572//---------------------------------------------------
573
574// Using struct create more flexible redirect policy
575type CustomRedirectPolicy struct {
576  // variables goes here
577}
578
579func (c *CustomRedirectPolicy) Apply(req *http.Request, via []*http.Request) error {
580  // Implement your logic here
581
582  // return nil for continue redirect otherwise return error to stop/prevent redirect
583  return nil
584}
585
586// Registering in resty
587client.SetRedirectPolicy(CustomRedirectPolicy{/* initialize variables */})
588```
589
590#### Custom Root Certificates and Client Certificates
591
592```go
593// Create a Resty Client
594client := resty.New()
595
596// Custom Root certificates, just supply .pem file.
597// you can add one or more root certificates, its get appended
598client.SetRootCertificate("/path/to/root/pemFile1.pem")
599client.SetRootCertificate("/path/to/root/pemFile2.pem")
600// ... and so on!
601
602// Adding Client Certificates, you add one or more certificates
603// Sample for creating certificate object
604// Parsing public/private key pair from a pair of files. The files must contain PEM encoded data.
605cert1, err := tls.LoadX509KeyPair("certs/client.pem", "certs/client.key")
606if err != nil {
607  log.Fatalf("ERROR client certificate: %s", err)
608}
609// ...
610
611// You add one or more certificates
612client.SetCertificates(cert1, cert2, cert3)
613```
614
615#### Custom Root Certificates and Client Certificates from string
616
617```go
618// Custom Root certificates from string
619// You can pass you certificates throught env variables as strings
620// you can add one or more root certificates, its get appended
621client.SetRootCertificateFromString("-----BEGIN CERTIFICATE-----content-----END CERTIFICATE-----")
622client.SetRootCertificateFromString("-----BEGIN CERTIFICATE-----content-----END CERTIFICATE-----")
623// ... and so on!
624
625// Adding Client Certificates, you add one or more certificates
626// Sample for creating certificate object
627// Parsing public/private key pair from a pair of files. The files must contain PEM encoded data.
628cert1, err := tls.X509KeyPair([]byte("-----BEGIN CERTIFICATE-----content-----END CERTIFICATE-----"), []byte("-----BEGIN CERTIFICATE-----content-----END CERTIFICATE-----"))
629if err != nil {
630  log.Fatalf("ERROR client certificate: %s", err)
631}
632// ...
633
634// You add one or more certificates
635client.SetCertificates(cert1, cert2, cert3)
636```
637
638#### Proxy Settings - Client as well as at Request Level
639
640Default `Go` supports Proxy via environment variable `HTTP_PROXY`. Resty provides support via `SetProxy` & `RemoveProxy`.
641Choose as per your need.
642
643**Client Level Proxy** settings applied to all the request
644
645```go
646// Create a Resty Client
647client := resty.New()
648
649// Setting a Proxy URL and Port
650client.SetProxy("http://proxyserver:8888")
651
652// Want to remove proxy setting
653client.RemoveProxy()
654```
655
656#### Retries
657
658Resty uses [backoff](http://www.awsarchitectureblog.com/2015/03/backoff.html)
659to increase retry intervals after each attempt.
660
661Usage example:
662
663```go
664// Create a Resty Client
665client := resty.New()
666
667// Retries are configured per client
668client.
669    // Set retry count to non zero to enable retries
670    SetRetryCount(3).
671    // You can override initial retry wait time.
672    // Default is 100 milliseconds.
673    SetRetryWaitTime(5 * time.Second).
674    // MaxWaitTime can be overridden as well.
675    // Default is 2 seconds.
676    SetRetryMaxWaitTime(20 * time.Second).
677    // SetRetryAfter sets callback to calculate wait time between retries.
678    // Default (nil) implies exponential backoff with jitter
679    SetRetryAfter(func(client *resty.Client, resp *resty.Response) (time.Duration, error) {
680        return 0, errors.New("quota exceeded")
681    })
682```
683
684Above setup will result in resty retrying requests returned non nil error up to
6853 times with delay increased after each attempt.
686
687You can optionally provide client with [custom retry conditions](https://pkg.go.dev/github.com/go-resty/resty/v2#RetryConditionFunc):
688
689```go
690// Create a Resty Client
691client := resty.New()
692
693client.AddRetryCondition(
694    // RetryConditionFunc type is for retry condition function
695    // input: non-nil Response OR request execution error
696    func(r *resty.Response, err error) bool {
697        return r.StatusCode() == http.StatusTooManyRequests
698    },
699)
700```
701
702Above example will make resty retry requests ended with `429 Too Many Requests`
703status code.
704
705Multiple retry conditions can be added.
706
707It is also possible to use `resty.Backoff(...)` to get arbitrary retry scenarios
708implemented. [Reference](retry_test.go).
709
710#### Allow GET request with Payload
711
712```go
713// Create a Resty Client
714client := resty.New()
715
716// Allow GET request with Payload. This is disabled by default.
717client.SetAllowGetMethodPayload(true)
718```
719
720#### Wanna Multiple Clients
721
722```go
723// Here you go!
724// Client 1
725client1 := resty.New()
726client1.R().Get("http://httpbin.org")
727// ...
728
729// Client 2
730client2 := resty.New()
731client2.R().Head("http://httpbin.org")
732// ...
733
734// Bend it as per your need!!!
735```
736
737#### Remaining Client Settings & its Options
738
739```go
740// Create a Resty Client
741client := resty.New()
742
743// Unique settings at Client level
744//--------------------------------
745// Enable debug mode
746client.SetDebug(true)
747
748// Assign Client TLSClientConfig
749// One can set custom root-certificate. Refer: http://golang.org/pkg/crypto/tls/#example_Dial
750client.SetTLSClientConfig(&tls.Config{ RootCAs: roots })
751
752// or One can disable security check (https)
753client.SetTLSClientConfig(&tls.Config{ InsecureSkipVerify: true })
754
755// Set client timeout as per your need
756client.SetTimeout(1 * time.Minute)
757
758
759// You can override all below settings and options at request level if you want to
760//--------------------------------------------------------------------------------
761// Host URL for all request. So you can use relative URL in the request
762client.SetHostURL("http://httpbin.org")
763
764// Headers for all request
765client.SetHeader("Accept", "application/json")
766client.SetHeaders(map[string]string{
767        "Content-Type": "application/json",
768        "User-Agent": "My custom User Agent String",
769      })
770
771// Cookies for all request
772client.SetCookie(&http.Cookie{
773      Name:"go-resty",
774      Value:"This is cookie value",
775      Path: "/",
776      Domain: "sample.com",
777      MaxAge: 36000,
778      HttpOnly: true,
779      Secure: false,
780    })
781client.SetCookies(cookies)
782
783// URL query parameters for all request
784client.SetQueryParam("user_id", "00001")
785client.SetQueryParams(map[string]string{ // sample of those who use this manner
786      "api_key": "api-key-here",
787      "api_secert": "api-secert",
788    })
789client.R().SetQueryString("productId=232&template=fresh-sample&cat=resty&source=google&kw=buy a lot more")
790
791// Form data for all request. Typically used with POST and PUT
792client.SetFormData(map[string]string{
793    "access_token": "BC594900-518B-4F7E-AC75-BD37F019E08F",
794  })
795
796// Basic Auth for all request
797client.SetBasicAuth("myuser", "mypass")
798
799// Bearer Auth Token for all request
800client.SetAuthToken("BC594900518B4F7EAC75BD37F019E08FBC594900518B4F7EAC75BD37F019E08F")
801
802// Enabling Content length value for all request
803client.SetContentLength(true)
804
805// Registering global Error object structure for JSON/XML request
806client.SetError(&Error{})    // or resty.SetError(Error{})
807```
808
809#### Unix Socket
810
811```go
812unixSocket := "/var/run/my_socket.sock"
813
814// Create a Go's http.Transport so we can set it in resty.
815transport := http.Transport{
816	Dial: func(_, _ string) (net.Conn, error) {
817		return net.Dial("unix", unixSocket)
818	},
819}
820
821// Create a Resty Client
822client := resty.New()
823
824// Set the previous transport that we created, set the scheme of the communication to the
825// socket and set the unixSocket as the HostURL.
826client.SetTransport(&transport).SetScheme("http").SetHostURL(unixSocket)
827
828// No need to write the host's URL on the request, just the path.
829client.R().Get("/index.html")
830```
831
832#### Bazel support
833
834Resty can be built, tested and depended upon via [Bazel](https://bazel.build).
835For example, to run all tests:
836
837```shell
838bazel test :go_default_test
839```
840
841#### Mocking http requests using [httpmock](https://github.com/jarcoal/httpmock) library
842
843In order to mock the http requests when testing your application you
844could use the `httpmock` library.
845
846When using the default resty client, you should pass the client to the library as follow:
847
848```go
849// Create a Resty Client
850client := resty.New()
851
852// Get the underlying HTTP Client and set it to Mock
853httpmock.ActivateNonDefault(client.GetClient())
854```
855
856More detailed example of mocking resty http requests using ginko could be found [here](https://github.com/jarcoal/httpmock#ginkgo--resty-example).
857
858## Versioning
859
860Resty releases versions according to [Semantic Versioning](http://semver.org)
861
862  * Resty v2 does not use `gopkg.in` service for library versioning.
863  * Resty fully adapted to `go mod` capabilities since `v1.10.0` release.
864  * 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`.
865  * 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.
866
867## Contribution
868
869I 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.
870
871BTW, 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.
872
873## Creator
874
875[Jeevanandam M.](https://github.com/jeevatkm) (jeeva@myjeeva.com)
876
877## Core Team
878
879Have a look on [Members](https://github.com/orgs/go-resty/teams/core/members) page.
880
881## Contributors
882
883Have a look on [Contributors](https://github.com/go-resty/resty/graphs/contributors) page.
884
885## License
886
887Resty released under MIT license, refer [LICENSE](LICENSE) file.
888