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