|
1 | 1 | # resty [](https://travis-ci.org/go-resty/resty) [](http://gocover.io/github.com/go-resty/resty) [](https://godoc.org/github.com/go-resty/resty) [](LICENSE)
|
2 | 2 |
|
3 |
| -Simple HTTP and REST client for Go inspired by Ruby rest-client |
| 3 | +Simple HTTP and REST client for Go inspired by Ruby rest-client. |
4 | 4 |
|
5 |
| -**Documentation is in progress.** |
| 5 | +#### Features |
| 6 | +* Get, Post, Put, Delete, Head, Patch and Options |
| 7 | +* Simple methods/chainable methods for settings and request |
| 8 | +* Request Body can be `string`, `[]byte`, `struct` and `map` |
| 9 | +* Response object gives you more possibility |
| 10 | + * Access as `[]byte` array - `response.Body` OR Access as `string` - `response.String()` |
| 11 | + * Know your `response.Time()` and when we `response.ReceivedAt` |
| 12 | + * Have a look [godoc](https://godoc.org/github.com/go-resty/resty#Response) |
| 13 | +* Automatic marshal and unmarshal for `JSON` and `XML` content type |
| 14 | + * Default is `JSON`, if you supply `struct/map` without header `Content-Type` |
| 15 | +* Easy to upload single or multiple files via `multipart/form-data` |
| 16 | +* Cookies for your request and CookieJar support |
| 17 | +* Authorization option of `Basic` and `Bearer` token |
| 18 | +* Set request `ContentLength` value for all request or particular request |
| 19 | +* Choose between HTTP and RESTful mode. Default is RESTful |
| 20 | + * `HTTP` - default upto 10 redirects and no automaic response unmarshal |
| 21 | + * `RESTful` - default no redirects and automatic response unmarshal for `JSON` & `XML` |
| 22 | +* Client settings like Timeout, RedirectPolicy and TLSClientConfig |
| 23 | +* Client API design |
| 24 | + * Have client level settings & options and also override at Request level if you want to |
| 25 | + * [Request](https://godoc.org/github.com/go-resty/resty#Client.OnBeforeRequest) and [Response](https://godoc.org/github.com/go-resty/resty#Client.OnAfterResponse) middleware |
| 26 | + * Create Multiple clients if want to `resty.New()` |
| 27 | + * goroutine concurrent safe |
| 28 | + * Debug mode - clean and informative logging presentation |
| 29 | + * Gzip - I'm not doing anything here. Go does it automatically |
| 30 | +* Well tested client library |
6 | 31 |
|
7 |
| -### Usage |
8 |
| -<pre>Documentation is in progress</pre> |
| 32 | +resty tested with Go 1.2 and above. |
| 33 | + |
| 34 | +## Installation |
| 35 | +#### Stable |
| 36 | +```sh |
| 37 | +go get gopkg.in/resty.v0 |
| 38 | +``` |
| 39 | +#### Latest |
| 40 | +```sh |
| 41 | +go get github.com/go-resty/resty |
| 42 | +``` |
| 43 | + |
| 44 | +## Usage |
| 45 | +Following samples will assist you to become as much comfortable as possible with resty library. Resty comes with ready to use DefaultClient. |
| 46 | + |
| 47 | +Import resty into your code and refer it as `resty`. |
| 48 | +```go |
| 49 | +import "gopkg.in/resty.v0" |
| 50 | +``` |
| 51 | + |
| 52 | +#### Simple GET |
| 53 | +```go |
| 54 | +// GET request |
| 55 | +resp, err := resty.R().Get("http://httpbin.org/get") |
| 56 | + |
| 57 | +// explore response object |
| 58 | +fmt.Printf("\nError: %v", err) |
| 59 | +fmt.Printf("\nResponse Status Code: %v", resp.StatusCode()) |
| 60 | +fmt.Printf("\nResponse Status: %v", resp.Status()) |
| 61 | +fmt.Printf("\nResponse Time: %v", resp.Time()) |
| 62 | +fmt.Printf("\nResponse Recevied At: %v", resp.ReceivedAt) |
| 63 | +fmt.Printf("\nResponse Body: %v", resp) |
| 64 | +// more... |
| 65 | + |
| 66 | +/* Output |
| 67 | +Error: <nil> |
| 68 | +Response Status Code: 200 |
| 69 | +Response Status: 200 OK |
| 70 | +Response Time: 644.290186ms |
| 71 | +Response Recevied At: 2015-09-15 12:05:28.922780103 -0700 PDT |
| 72 | +Response Body: { |
| 73 | + "args": {}, |
| 74 | + "headers": { |
| 75 | + "Accept-Encoding": "gzip", |
| 76 | + "Host": "httpbin.org", |
| 77 | + "User-Agent": "go-resty v0.1 - https://github.com/go-resty/resty" |
| 78 | + }, |
| 79 | + "origin": "0.0.0.0", |
| 80 | + "url": "http://httpbin.org/get" |
| 81 | +} |
| 82 | +*/ |
| 83 | +``` |
| 84 | +#### Ehanced GET |
| 85 | +```go |
| 86 | +resp, err := resty.R(). |
| 87 | + SetQueryParams(map[string]string{ |
| 88 | + "page_no": "1", |
| 89 | + "limit": "20", |
| 90 | + "sort":"name", |
| 91 | + "order": "asc", |
| 92 | + "random":strconv.FormatInt(time.Now().Unix(), 10), |
| 93 | + }). |
| 94 | + SetHeader("Accept", "application/json"). |
| 95 | + SetAuthToken("BC594900518B4F7EAC75BD37F019E08FBC594900518B4F7EAC75BD37F019E08F"). |
| 96 | + Get("/search_result") |
| 97 | +``` |
| 98 | + |
| 99 | +#### Various POST method combinations |
| 100 | +```go |
| 101 | +// POST JSON string |
| 102 | +// No need to set content type, if you have client level setting |
| 103 | +resp, err := resty.R(). |
| 104 | + SetHeader("Content-Type", "application/json"). |
| 105 | + SetBody(`{"username":"testuser", "password":"testpass"}`). |
| 106 | + SetResult(&AuthSuccess{}). |
| 107 | + Post("https://myapp.com/login") |
| 108 | + |
| 109 | +// POST []byte array |
| 110 | +// No need to set content type, if you have client level setting |
| 111 | +resp, err := resty.R(). |
| 112 | + SetHeader("Content-Type", "application/json"). |
| 113 | + SetBody([]byte(`{"username":"testuser", "password":"testpass"}`)). |
| 114 | + SetResult(&AuthSuccess{}). |
| 115 | + Post("https://myapp.com/login") |
| 116 | + |
| 117 | +// POST Struct, default is JSON content type. No need to set one |
| 118 | +resp, err := resty.R(). |
| 119 | + SetBody(User{Username: "testuser", Password: "testpass"}). |
| 120 | + SetResult(&AuthSuccess{}). |
| 121 | + SetError(&AuthError{}). |
| 122 | + Post("https://myapp.com/login") |
| 123 | + |
| 124 | +// POST Map, default is JSON content type. No need to set one |
| 125 | +resp, err := resty.R(). |
| 126 | + SetBody(map[string]interface{}{"username": "testuser", "password": "testpass"}). |
| 127 | + SetResult(&AuthSuccess{}). |
| 128 | + SetError(&AuthError{}). |
| 129 | + Post("https://myapp.com/login") |
| 130 | + |
| 131 | +// POST of raw bytes for file upload. For example: upload file to Dropbox |
| 132 | +file, _ := os.Open("/Users/jeeva/mydocument.pdf") |
| 133 | +fileBytes, _ := ioutil.ReadAll(file) |
| 134 | + |
| 135 | +// See we are not setting content-type header, since go-resty automatically detects Content-Type for you |
| 136 | +resp, err := resty.R(). |
| 137 | + SetBody(fileBytes). |
| 138 | + SetContentLength(true). // Dropbox expects this value |
| 139 | + SetAuthToken("<you-auth-token>"). |
| 140 | + SetError(&DropboxError{}). |
| 141 | + Post("https://content.dropboxapi.com/1/files_put/auto/resty/mydocument.pdf") // for upload Dropbox supports PUT too |
| 142 | +``` |
| 143 | + |
| 144 | +#### Sample PUT |
| 145 | +You can use various combinations of `PUT` method call like demonstrated for `POST`. |
| 146 | +```go |
| 147 | +// Just one sample of PUT, refer POST for more combination |
| 148 | +// request goes as JSON content type |
| 149 | +// No need to set auth token, error, if you have client level settings |
| 150 | +resp, err := resty.R(). |
| 151 | + SetBody(Article{ |
| 152 | + Title: "go-resty", |
| 153 | + Content: "This is my article content, oh ya!", |
| 154 | + Author: "Jeevanandam M", |
| 155 | + Tags: []string{"article", "sample", "resty"}, |
| 156 | + }). |
| 157 | + SetAuthToken("C6A79608-782F-4ED0-A11D-BD82FAD829CD"). |
| 158 | + SetError(&Error{}). |
| 159 | + Put("https://myapp.com/article/1234") |
| 160 | +``` |
| 161 | + |
| 162 | +#### Sample PATCH |
| 163 | +You can use various combinations of `PATCH` method call like demonstrated for `POST`. |
| 164 | +```go |
| 165 | +// Just one sample of PATCH, refer POST for more combination |
| 166 | +// request goes as JSON content type |
| 167 | +// No need to set auth token, error, if you have client level settings |
| 168 | +resp, err := resty.R(). |
| 169 | + SetBody(Article{ |
| 170 | + Tags: []string{"new tag1", "new tag2"}, |
| 171 | + }). |
| 172 | + SetAuthToken("C6A79608-782F-4ED0-A11D-BD82FAD829CD"). |
| 173 | + SetError(&Error{}). |
| 174 | + Patch("https://myapp.com/article/1234") |
| 175 | +``` |
| 176 | + |
| 177 | +#### Sample DELETE, HEAD, OPTIONS |
| 178 | +```go |
| 179 | +// DELETE a article |
| 180 | +// No need to set auth token, error, if you have client level settings |
| 181 | +resp, err := resty.R(). |
| 182 | + SetAuthToken("C6A79608-782F-4ED0-A11D-BD82FAD829CD"). |
| 183 | + SetError(&Error{}). |
| 184 | + Delete("https://myapp.com/article/1234") |
| 185 | + |
| 186 | +// HEAD of resource |
| 187 | +// No need to set auth token, if you have client level settings |
| 188 | +resp, err := resty.R(). |
| 189 | + SetAuthToken("C6A79608-782F-4ED0-A11D-BD82FAD829CD"). |
| 190 | + Head("https://myapp.com/video/hi-res-video") |
| 191 | + |
| 192 | +// OPTIONS of resource |
| 193 | +// No need to set auth token, if you have client level settings |
| 194 | +resp, err := resty.R(). |
| 195 | + SetAuthToken("C6A79608-782F-4ED0-A11D-BD82FAD829CD"). |
| 196 | + Options("https://myapp.com/server/nyc-dc-01") |
| 197 | +``` |
| 198 | + |
| 199 | +### Multipart File(s) upload |
| 200 | +```go |
| 201 | +// Single file scenario |
| 202 | +resp, err := resty.R(). |
| 203 | + SetFile("profile_img", "/Users/jeeva/test-img.png"). |
| 204 | + Post("http://myapp.com/upload") |
| 205 | + |
| 206 | +// Multiple files scenario |
| 207 | +resp, err := resty.R(). |
| 208 | + SetFiles(map[string]string{ |
| 209 | + "profile_img": "/Users/jeeva/test-img.png", |
| 210 | + "notes": "/Users/jeeva/text-file.txt", |
| 211 | + }). |
| 212 | + Post("http://myapp.com/upload") |
| 213 | + |
| 214 | +// Multipart of form fields and files |
| 215 | +resp, err := resty.R(). |
| 216 | + SetFiles(map[string]string{ |
| 217 | + "profile_img": "/Users/jeeva/test-img.png", |
| 218 | + "notes": "/Users/jeeva/text-file.txt", |
| 219 | + }). |
| 220 | + SetFormData(map[string]string{ |
| 221 | + "first_name": "Jeevanandam", |
| 222 | + "last_name": "M", |
| 223 | + "zip_code": "00001", |
| 224 | + "city": "my city", |
| 225 | + "access_token": "C6A79608-782F-4ED0-A11D-BD82FAD829CD", |
| 226 | + }). |
| 227 | + Post("http://myapp.com/profile") |
| 228 | +``` |
| 229 | + |
| 230 | +#### Sample Form submision |
| 231 | +```go |
| 232 | +// just mentioning about POST as an example with simple flow |
| 233 | +// User Login |
| 234 | +resp, err := resty.R(). |
| 235 | + SetFormData(map[string]string{ |
| 236 | + "username": "jeeva", |
| 237 | + "password": "mypass", |
| 238 | + }). |
| 239 | + Post("http://myapp.com/login") |
| 240 | + |
| 241 | +// Followed by profile update |
| 242 | +resp, err := resty.R(). |
| 243 | + SetFormData(map[string]string{ |
| 244 | + "first_name": "Jeevanandam", |
| 245 | + "last_name": "M", |
| 246 | + "zip_code": "00001", |
| 247 | + "city": "new city update", |
| 248 | + }). |
| 249 | + Post("http://myapp.com/profile") |
| 250 | +``` |
| 251 | + |
| 252 | +#### Request and Response Middleware |
| 253 | +```go |
| 254 | +// Registering Request Middleware |
| 255 | +resty.OnBeforeRequest(func(c *Client, r *Request) error { |
| 256 | + // Now you have access to Client and current Request object |
| 257 | + // manipulate it as per your need |
| 258 | + }) |
| 259 | + |
| 260 | +// Registering Response Middleware |
| 261 | +resty.OnAfterResponse(func(c *Client, r *Response) error { |
| 262 | + // Now you have access to Client and current Response object |
| 263 | + // manipulate it as per your need |
| 264 | + }) |
| 265 | +``` |
| 266 | + |
| 267 | +#### Choose REST or HTTP mode |
| 268 | +```go |
| 269 | +// HTTP mode |
| 270 | +resty.SetHTTPMode() |
| 271 | + |
| 272 | +// REST mode. Default one |
| 273 | +resty.SetRESTMode() |
| 274 | +``` |
| 275 | + |
| 276 | +#### Wanna Multiple Clients |
| 277 | +```go |
| 278 | +// Here you go! |
| 279 | +// Client 1 |
| 280 | +client1 := resty.New() |
| 281 | +client1.R().Get("http://httpbin.org") |
| 282 | +// ... |
| 283 | + |
| 284 | +// Client 2 |
| 285 | +client2 := resty.New() |
| 286 | +client1.R().Head("http://httpbin.org") |
| 287 | +// ... |
| 288 | + |
| 289 | +// Bend it as per your need!!! |
| 290 | +``` |
| 291 | + |
| 292 | +#### Remaining Client Settings & its Options |
| 293 | +```go |
| 294 | +// Unique settings at Client level |
| 295 | +//-------------------------------- |
| 296 | +// Enable debug mode |
| 297 | +resty.SetDebug(true) |
| 298 | + |
| 299 | +// Using you custom log writer |
| 300 | +logFile, _ := os.OpenFile("/Users/jeeva/go-resty.log", os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666) |
| 301 | +resty.SetLogger(logFile) |
| 302 | + |
| 303 | +// Assign Client Redirect Policy. Create one as per you need |
| 304 | +resty.SetRedirectPolicy(FlexibleRedirectPolicy(15)) |
| 305 | + |
| 306 | +// Assign Client TLSClientConfig |
| 307 | +// One can set custom root-certificate. Refer: http://golang.org/pkg/crypto/tls/#example_Dial |
| 308 | +resty.SetTLSClientConfig(&tls.Config{ RootCAs: roots }) |
| 309 | + |
| 310 | +// or One can disable security check (https) |
| 311 | +resty.SetTLSClientConfig(&tls.Config{ InsecureSkipVerify: true }) |
| 312 | + |
| 313 | +// Set client timeout as per your need |
| 314 | +resty.SetTimeout(time.Duration(1 * time.Minute)) |
| 315 | + |
| 316 | + |
| 317 | +// You can override all below settings and options at request level if you want to |
| 318 | +//-------------------------------------------------------------------------------- |
| 319 | +// Host URL for all request. So you can use relative URL in the request |
| 320 | +resty.SetHostURL("http://httpbin.org") |
| 321 | + |
| 322 | +// Headers for all request |
| 323 | +resty.SetHeader("Accept", "application/json") |
| 324 | +resty.SetHeaders(map[string]string{ |
| 325 | + "Content-Type": "application/json", |
| 326 | + "User-Agent": "My cutsom User Agent String", |
| 327 | + }) |
| 328 | + |
| 329 | +// Cookies for all request |
| 330 | +resty.SetCookie(&http.Cookie{ |
| 331 | + Name:"go-resty", |
| 332 | + Value:"This is cookie value", |
| 333 | + Path: "/", |
| 334 | + Domain: "sample.com", |
| 335 | + MaxAge: 36000, |
| 336 | + HttpOnly: true, |
| 337 | + Secure: false, |
| 338 | + }) |
| 339 | +resty.SetCookies(cookies) |
| 340 | + |
| 341 | +// URL query parameters for all request |
| 342 | +resty.SetQueryParam("user_id", "00001") |
| 343 | +resty.SetQueryParams(map[string]string{ // sample of those who use this manner |
| 344 | + "api_key": "api-key-here", |
| 345 | + "api_secert": "api-secert", |
| 346 | + }) |
| 347 | + |
| 348 | +// Form data for all request. Typically used with POST and PUT |
| 349 | +resty.SetFormData(map[string]string{ |
| 350 | + "access_token": "BC594900-518B-4F7E-AC75-BD37F019E08F", |
| 351 | + }) |
| 352 | + |
| 353 | +// Basic Auth for all request |
| 354 | +resty.SetBasicAuth("myuser", "mypass") |
| 355 | + |
| 356 | +// Bearer Auth Token for all request |
| 357 | +resty.SetAuthToken("BC594900518B4F7EAC75BD37F019E08FBC594900518B4F7EAC75BD37F019E08F") |
| 358 | + |
| 359 | +// Enabling Content length value for all request |
| 360 | +resty.SetContentLength(true) |
| 361 | + |
| 362 | +// Registering global Error object structure for JSON/XML request |
| 363 | +resty.SetError(&Error{}) |
| 364 | +``` |
9 | 365 |
|
10 | 366 | ### Versioning
|
11 | 367 | * resty release version according to [Semantic Versioning](http://semver.org)
|
| 368 | + |
| 369 | +### Contributing |
| 370 | +Welcome! If you find any improvement or issue you want to fix. Feel free to send a pull request, I like pull requests that include tests case for fix/enhancement. Did my best to bring pretty good code coverage and feel free to write tests. |
| 371 | + |
| 372 | +BTW, I'd like to know what you think about go-resty. Kindly open an issue or send me an email; it'd mean a lot to me. |
12 | 373 |
|
13 | 374 | ### License
|
14 | 375 | resty released under MIT license, refer [LICENSE](LICENSE) file.
|
0 commit comments