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