goreq

package module
v0.0.0-...-2e3372c Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 27, 2018 License: MIT Imports: 19 Imported by: 4

README

goreq

GoDoc Drone Build Status Go Report Card

A Simplified Http Client. Its initial codes are cloned from HttpRequest. I have refactored the codes and make it more friendly to programmers. And some bugs are fixed and new features are added.

Major changes include:

  • can send any string or bytes in body
  • can set a shared client for concurrency
  • won't clear setting actively
  • ......

You can see the release notes for details.

Installation

$ go get github.com/smallnest/goreq

Usage

why you should use goreq

goreq comes from gorequest but it added some new features and fixed some bugs. The initial functions and major functions are from gorequest. Thanks to @parnurzeal and other contributors. Why have I not created pull requests to gorequest and created a new repository? I want to refactor it a lot and add features quickly.

GoReq makes http thing more simple for you, using fluent styles to make http client more awesome. You can control headers, timeout, query parameters, binding response and others in one line:

Before

client := &http.Client{
  CheckRedirect: redirectPolicyFunc,
}

req, err := http.NewRequest("GET", "http://example.com", nil)

req.Header.Add("If-None-Match", `W/"wyzzy"`)
resp, err := client.Do(req)

Using GoReq

resp, body, errs := goreq.New().Get("http://example.com").
  RedirectPolicy(redirectPolicyFunc).
  SetHeader("If-None-Match", `W/"wyzzy"`).
  End()
Http Methods
GET
resp, body, err := goreq.New().Get("http://httpbin.org/get").End()
DELETE
q := `{"Name":"Jerry"}`
resp, _, err := goreq.New().Delete("http://httpbin.org/delete").ContentType("json").SendMapString(q).End()
HEAD
resp, body, err := goreq.New().Head("http://httpbin.org/headers").SendRawString("hello world").End()
POST
resp, body, err := goreq.New().Post("http://httpbin.org/post").SendRawString("hello world").End()
PUT
q := `{"Name":"Jerry"}`
resp, body, err := goreq.New().Put("http://httpbin.org/put").ContentType("json").SendMapString(q).End()
PATCH
q := `{"Name":"Jerry"}`
resp, body, err := goreq.New().Patch("http://httpbin.org/patch").ContentType("json").SendMapString(q).End()
Header

You can set one Header by:


or set some headers by json:


or set some headers by struct:


Proxy

In the case when you are behind proxy, GoRequest can handle it easily with Proxy func:

request := goreq.New().Proxy("http://proxy:999")
resp, body, errs := request.Get("http://example-proxy.com").End()

Socks5 will be supported in future.

Timeout

Timeout can be set in any time duration using time package:

request := goreq.New().Timeout(2*time.Millisecond)
resp, body, errs:= request.Get("http://example.com").End()

Timeout func defines both dial + read/write timeout to the specified time parameter.

SSL
Basic Auth

To add a basic authentication header:

request := goreq.New().SetBasicAuth("username", "password") resp, body, errs := request.Get("http://example-proxy.com").End(.End())

Query Parameter

Query function accepts either json string or query strings which will form a query-string in url of GET method or body of POST method. For example, making "/search?query=bicycle&size=50x50&weight=20kg" using GET method:

     goreq.New().
        Get("/search").
        Query(`{ "query": "bicycle" }`).
        Query(`{ "size": "50x50" }`).
        Query(`{ "weight": "20kg" }`).
        End()

It also support query string:

      goreq.New().
        Get("/search").
        Query("query=bicycle&size=50x50").
        Query("weight=20kg").
        End()

even you can pass a struct:

      qq := struct {
              Query1 string `json:"query1"`
              Query2 string `json:"query2"`
          }{
              Query1: "test1",
              Query2: "test2",
          }
      goreq.New().
        Get("/search").
        Query(qq).
        End()

Param can be used to set query value that contains ";" like fields=f1;f2;f3

Request Body

For POST, PUT, PATCH, you can set content of request BODY.. It is convenient to BODY content.

JSON

You can use SendMapString or SendStruct to set JSON content. You should set content type to "application/json" by:

goreq.New().Post("/user").ContentType("json")

or

goreq.New().Post("/user").SetHeader("application/json")

GoReq will parse struct, json string or query string and rebuild the json content:

      type BrowserVersionSupport struct {
        Chrome string
        Firefox string
      }
      ver := BrowserVersionSupport{ Chrome: "37.0.2041.6", Firefox: "30.0" }
      goreq.New().
        Post("/update_version").
        SendStruct(ver).
        SendStruct(`{"Safari":"5.1.10"}`).
        End()

or

      goreq.New().
        Post("/search").
        SendMapString("query=bicycle&size=50x50").
        SendMapString(`{ "wheel": "4"}`).
        End()
Form

If you set Content-Type as "application/x-www-form-urlencoded", GoReq rebuilds the below data into form style:

      goreq.New().
        Post("/search").
        ContentType("form").
        SendMapString("query=bicycle&size=50x50").
        SendMapString(`{ "wheel": "4"}`).
        End()
Raw String

If you want upload XML or other plain text, you can use this method:

        goreq.New().
        Post("/search").
        ContentType("text").
        SendRawString("hello world").
        End()
Raw Bytes

Even you can upload raw bytes:

        goreq.New().
        Post("/search").
        ContentType("stream").
        SendRawBytes([]byte("hello world")).
        End()
Bind Response Body

You can bind response body to a struct:

    type Person struct {
        Name string
    }

    var friend Person
        _, _, err := goreq.New().Get(ts.URL).
        BindBody(&friend).
        End()
Callback

GoReqalso supports callback function to handle response:

func printStatus(resp goreq.Response, body string, errs []error){
  fmt.Println(resp.Status)
}
goreq.New().Get("http://example.com").End(printStatus)
Debug

For deugging, GoReq leverages httputil to dump details of every request/response. You can just use SetDebug to enable/disable debug mode and SetLogger to set your own choice of logger.

Share Client

For concurrency, you can use a shared client in multiple GoReq instances:

    sa := New().Get(ts.URL + case1_empty)
    sa.End()

    client := sa.Client;

    goreq.New().Get(ts.URL+case2_set_header).
    SetHeader("API-Key", "fookey").
    SetClient(client).
    End()
Reset

You can reset GoReq and use it send another request. It only keep the client and reset other fields.

goreq.New().Get("http://example.com").Reset()
Retry

You can set a retry value and GoReq will retry until the value if it fails. So goreq sends request at most retry + 1 times.

_, _, err := New().Get(ts.URL).
    Retry(3, 100, nil).
    End()

License

goreq is MIT License.

Documentation

Overview

Package goreq is a simplified http client. Its initial codes are cloned from [HttpRequest](https://github.com/parnurzeal/gorequest). I have refactored the codes and make it more friendly to programmers. And some bugs are fixed and new features are added. goreq makes http thing more simple for you, using fluent styles to make http client more awesome. You can control headers, timeout, query parameters, binding response and others in one line:

Before

client := &http.Client{
	 CheckRedirect: redirectPolicyFunc,
}

req, err := http.NewRequest("GET", "http://example.com", nil) req.Header.Add("If-None-Match", `W/"wyzzy"`) resp, err := client.Do(req)

Using GoReq

resp, body, errs := goreq.New().Get("http://example.com").

RedirectPolicy(redirectPolicyFunc).
SetHeader("If-None-Match", `W/"wyzzy"`).
End()

Index

Examples

Constants

View Source
const (
	POST    = "POST"
	GET     = "GET"
	HEAD    = "HEAD"
	PUT     = "PUT"
	DELETE  = "DELETE"
	PATCH   = "PATCH"
	OPTIONS = "OPTIONS"
)

HTTP methods we support

Variables

View Source
var ShortContentTypes = map[string]string{
	"html":       "text/html",
	"text":       "text/plain",
	"json":       "application/json",
	"xml":        "application/xml",
	"urlencoded": "application/x-www-form-urlencoded",
	"form":       "application/x-www-form-urlencoded",
	"form-data":  "application/x-www-form-urlencoded",
	"stream":     "application/octet-stream",
}

ShortContentTypes defines some short content types.

Functions

This section is empty.

Types

type GoReq

type GoReq struct {
	URL           string
	Host          string
	Method        string
	Header        map[string]string
	Data          map[string]interface{}
	FormData      url.Values
	QueryData     url.Values
	RawStringData string
	RawBytesData  []byte
	FilePath      string
	FileParam     string
	Client        *http.Client
	CheckRedirect func(r *http.Request, v []*http.Request) error
	Transport     *http.Transport
	Cookies       []*http.Cookie
	Errors        []error
	BasicAuth     struct{ Username, Password string }
	Debug         bool
	CurlCommand   bool
	// contains filtered or unexported fields
}

A GoReq is a object storing all request data for client.

func New

func New() *GoReq

New returns a new GoReq object.

func (*GoReq) AddCookie

func (gr *GoReq) AddCookie(c *http.Cookie) *GoReq

AddCookie adds a cookie to the request. The behavior is the same as AddCookie on Request from net/http

func (*GoReq) AddCookies

func (gr *GoReq) AddCookies(cookies []*http.Cookie) *GoReq

AddCookies is a convenient method to add multiple cookies

func (*GoReq) BindBody

func (gr *GoReq) BindBody(bindResponseBody interface{}) *GoReq

BindBody set bind object for response.

For example:

type Person struct {
    Name string
}

var friend Person
response, _, errs := request.Post("http://example.com").BindBody(&friend).End()

func (*GoReq) BindHost

func (gr *GoReq) BindHost(host string) *GoReq

func (*GoReq) ContentType

func (gr *GoReq) ContentType(typeStr string) *GoReq

ContentType is a convenience function to specify the data type to send instead of SetHeader("Content-Type", "......"). For example, to send data as `application/x-www-form-urlencoded` :

goreq.New().
  Post("/recipe").
  ContentType("application/json").
  SendMapString(`{ "name": "egg benedict", "category": "brunch" }`).
  End()

This will POST the body "name=egg benedict&category=brunch" to url /recipe GoReq supports abbreviation Types:

"html" as "text/html"
"text" as "text/plain"
"json" as "application/json" uses
"xml" as "application/xml"
"urlencoded", "form" or "form-data" as "application/x-www-form-urlencoded"
"stream" as "application/octet-stream"

func (*GoReq) Delete

func (gr *GoReq) Delete(targetURL string) *GoReq

Delete is used to set DELETE HttpMethod with a url.

Example
package main

import (
	"fmt"

	"github.com/smallnest/goreq"
)

func main() {
	q := `{"Name":"Jerry"}`
	resp, _, err := goreq.New().
		Delete("http://httpbin.org/delete").
		ContentType("json").
		SendMapString(q).
		End()

	fmt.Println(resp.StatusCode == 200)
	fmt.Println(len(err) == 0)
}
Output:

true
true

func (*GoReq) End

func (gr *GoReq) End(callback ...func(response Response, body string, errs []error)) (Response, string, []error)

End is the most important function that you need to call when ending the chain. The request won't proceed without calling it. End function returns Response which matchs the structure of Response type in Golang's http package (but without Body data). The body data itself returns as a string in a 2nd return value. Lastly but worth noticing, error array (NOTE: not just single error value) is returned as a 3rd value and nil otherwise.

For example:

resp, body, errs := goreq.New().Get("http://www.google.com").End()
if (errs != nil) {
  fmt.Println(errs)
}
fmt.Println(resp, body)

Moreover, End function also supports callback which you can put as a parameter. This extends the flexibility and makegr *GoReq fun and clean! You can use GoReq in whatever style you love!

For example:

func printBody(resp goreq.Response, body string, errs []error){
  fmt.Println(resp.Status)
}
goreq.New().Get("http://www..google.com").End(printBody)

func (*GoReq) EndBytes

func (gr *GoReq) EndBytes(callback ...func(response Response, body []byte, errs []error)) (Response, []byte, []error)

EndBytes should be used when you want the body as bytes. The callbacks work the same way as with `End`, except that a byte array is used instead of a string.

func (*GoReq) Get

func (gr *GoReq) Get(targetURL string) *GoReq

Get is used to set GET HttpMethod with a url.

Example
package main

import (
	"fmt"

	"github.com/smallnest/goreq"
)

func main() {
	resp, body, err := goreq.New().
		Get("http://httpbin.org/get").
		End()

	fmt.Println(resp.StatusCode == 200)
	fmt.Println(len(err) == 0)
	fmt.Println(body != "")
}
Output:

true
true
true

func (*GoReq) Head

func (gr *GoReq) Head(targetURL string) *GoReq

Head is used to set HEAD HttpMethod with a url.

Example
package main

import (
	"fmt"

	"github.com/smallnest/goreq"
)

func main() {
	resp, body, err := goreq.New().
		Head("http://httpbin.org/headers").
		SendRawString("hello world").
		End()

	fmt.Println(resp.StatusCode == 200)
	fmt.Println(len(err) == 0)
	fmt.Println(body == "")
}
Output:

true
true
true

func (*GoReq) Options

func (gr *GoReq) Options(targetURL string) *GoReq

Options is used to set OPTIONS HttpMethod with a url.

func (*GoReq) Param

func (gr *GoReq) Param(key string, value string) *GoReq

Param accepts as Go conventions ; as a synonym for &. (https://github.com/golang/go/issues/2210) Thus, Query won't accept ; in a query string if we provide something like fields=f1;f2;f3 This Param is then created as an alternative method to solve this.

func (*GoReq) Patch

func (gr *GoReq) Patch(targetURL string) *GoReq

Patch is used to set PATCH HttpMethod with a url.

Example
package main

import (
	"fmt"

	"strings"

	"github.com/smallnest/goreq"
)

func main() {
	q := `{"Name":"Jerry"}`
	resp, body, err := goreq.New().
		Patch("http://httpbin.org/patch").
		ContentType("json").
		SendMapString(q).
		End()

	fmt.Println(resp.StatusCode == 200)
	fmt.Println(len(err) == 0)
	fmt.Println(strings.Contains(body, "Jerry"))
}
Output:

true
true
true

func (*GoReq) Post

func (gr *GoReq) Post(targetURL string) *GoReq

Post is used to set POST HttpMethod with a url.

Example
package main

import (
	"fmt"

	"strings"

	"github.com/smallnest/goreq"
)

func main() {
	resp, body, err := goreq.New().
		Post("http://httpbin.org/post").
		SendRawString("hello world").
		End()

	fmt.Println(resp.StatusCode == 200)
	fmt.Println(len(err) == 0)
	fmt.Println(strings.Contains(body, "hello world"))
}
Output:

true
true
true

func (*GoReq) Proxy

func (gr *GoReq) Proxy(proxyURL string) *GoReq

Proxy function accepts a proxy url string to setup proxy url for any request. It provides a convenience way to setup proxy which have advantages over usual old ways. One example is you might try to set `http_proxy` environment. This means you are setting proxy up for all the requests. You will not be able to send different request with different proxy unless you change your `http_proxy` environment again. Another example is using Golang proxy setting. This is normal prefer way to do but too verbase compared to GoReq's Proxy:

goreq.New().Proxy("http://myproxy:9999").
  Post("http://www.google.com").
  End()

To set no_proxy, just put empty string to Proxy func:

goreq.New().Proxy("").
  Post("http://www.google.com").
  End()

func (*GoReq) Put

func (gr *GoReq) Put(targetURL string) *GoReq

Put is used to set PUT HttpMethod with a url.

Example
package main

import (
	"fmt"

	"strings"

	"github.com/smallnest/goreq"
)

func main() {
	q := `{"Name":"Jerry"}`
	resp, body, err := goreq.New().
		Put("http://httpbin.org/put").
		ContentType("json").
		SendMapString(q).
		End()

	fmt.Println(resp.StatusCode == 200)
	fmt.Println(len(err) == 0)
	fmt.Println(strings.Contains(body, "Jerry"))
}
Output:

true
true
true

func (*GoReq) Query

func (gr *GoReq) Query(content interface{}) *GoReq

Query function accepts either json string or query strings which will form a query-string in url of GET method or body of POST method. For example, making "/search?query=bicycle&size=50x50&weight=20kg" using GET method:

goreq.New().
  Get("/search").
  Query(`{ "query": "bicycle" }`).
  Query(`{ "size": "50x50" }`).
  Query(`{ "weight": "20kg" }`).
  End()

Or you can put multiple json values:

goreq.New().
  Get("/search").
  Query(`{ "size": "50x50", "weight":"20kg" }`).
  End()

Strings are also acceptable:

goreq.New().
  Get("/search").
  Query("query=bicycle&size=50x50").
  Query("weight=20kg").
  End()

Or even Mixed! :)

goreq.New().
  Get("/search").
  Query("query=bicycle").
  Query(`{ "size": "50x50", "weight":"20kg" }`).
  End()

func (*GoReq) RedirectPolicy

func (gr *GoReq) RedirectPolicy(policy func(req Request, via []Request) error) *GoReq

RedirectPolicy is used to set redirect policy.

func (*GoReq) Reset

func (gr *GoReq) Reset() *GoReq

Reset is used to clear GoReq data for another new request only keep client and logger.

Example
package main

import (
	"fmt"

	"github.com/smallnest/goreq"
)

func main() {

	gr := goreq.New()
	gr.Get("http://httpbin.org/get").
		End()

	resp, body, err := gr.Reset().Get("http://httpbin.org/").
		End()

	fmt.Println(resp.StatusCode == 200)
	fmt.Println(len(err) == 0)
	fmt.Println(body != "")
}
Output:

true
true
true

func (*GoReq) Retry

func (gr *GoReq) Retry(retryCount int, retryTimeout int, retryOnHTTPStatus []int) *GoReq

Retry is used to retry to send requests if servers return unexpected status. So GoReq tries at most retryCount + 1 times and request interval is retryTimeout. You can indicate which status GoReq should retry in case of. If it is nil, retry only when status code >= 400

For example:

_, _, err := New().Get("http://example.com/a-wrong-url").
Retry(3, 100, nil).
End()

func (*GoReq) SendFile

func (gr *GoReq) SendFile(paramName, filePath string) *GoReq

SendFile posts a file to server.

Example
package main

import (
	"github.com/smallnest/goreq"
)

func main() {
	_, _, _ = goreq.New().
		Post("http://example.com/upload").
		SendFile("test", "LICENSE").
		EndBytes()

}
Output:

func (*GoReq) SendMapString

func (gr *GoReq) SendMapString(content string) *GoReq

SendMapString returns *GoReq's itself for any next chain and takes content string as a parameter. Its duty is to transform json String or query Strings into s.Data (map[string]interface{}) which later changes into appropriate format such as json, form, text, etc. in the End func. SendMapString function accepts either json string or other strings which is usually used to assign data to POST or PUT method. you can pass a json string:

goreq.New().
  Post("/search").
  SendMapString(`{ "query": "sushi" }`).
  End()

Or a query string:

goreq.New().
  Post("/search").
  SendMapString("query=tonkatsu").
  End()

You can also do multiple chain of Send:

goreq.New().
  Post("/search").
  SendMapString("query=bicycle&size=50x50").
  SendMapString(`{ "wheel": "4"}`).
  End()

func (*GoReq) SendRawBytes

func (gr *GoReq) SendRawBytes(content []byte) *GoReq

SendRawBytes returns *GoReq's itself for any next chain and takes content string as a parameter. Its duty is to transform []byte into gr.RawBytesData and send raw bytes in request body.

func (*GoReq) SendRawString

func (gr *GoReq) SendRawString(content string) *GoReq

SendRawString returns *GoReq's itself for any next chain and takes content string as a parameter. Its duty is to transform String into gr.RawStringData and send raw string in request body.

func (*GoReq) SendStruct

func (gr *GoReq) SendStruct(content interface{}) *GoReq

SendStruct (similar to SendMapString) returns *GoReq's itself for any next chain and takes content interface{} as a parameter. Its duty is to transfrom interface{} (implicitly always a struct) into s.Data (map[string]interface{}) which later changes into appropriate format such as json, form, text, etc. in the End() func. You can pass a struct to it:

type BrowserVersionSupport struct {
  Chrome string
  Firefox string
}
ver := BrowserVersionSupport{ Chrome: "37.0.2041.6", Firefox: "30.0" }
goreq.New().
  Post("/update_version").
  SendStruct(ver).
  SendStruct(`{"Safari":"5.1.10"}`).
  End()

func (*GoReq) SetBasicAuth

func (gr *GoReq) SetBasicAuth(username string, password string) *GoReq

SetBasicAuth sets the basic authentication header Example. To set the header for username "myuser" and password "mypass"

goreq.New()
  Post("/gamelist").
  SetBasicAuth("myuser", "mypass").
  End()

func (*GoReq) SetClient

func (gr *GoReq) SetClient(client *http.Client) *GoReq

SetClient ise used to set a shared http.Client

Example
package main

import (
	"fmt"

	"net/http"

	"github.com/smallnest/goreq"
)

func main() {
	client := &http.Client{}
	resp, body, err := goreq.New().SetClient(client).
		Get("http://httpbin.org/get").
		End()

	fmt.Println(resp.StatusCode == 200)
	fmt.Println(len(err) == 0)
	fmt.Println(body != "")
}
Output:

true
true
true

func (*GoReq) SetCurlCommand

func (gr *GoReq) SetCurlCommand(enable bool) *GoReq

SetCurlCommand enables the curlcommand mode which display a CURL command line

func (*GoReq) SetDebug

func (gr *GoReq) SetDebug(enable bool) *GoReq

SetDebug enables the debug mode which logs request/response detail

func (*GoReq) SetHeader

func (gr *GoReq) SetHeader(param string, value string) *GoReq

SetHeader is used for setting header fields. Example. To set `Accept` as `application/json`

goreq.New().
  Post("/gamelist").
  SetHeader("Accept", "application/json").
  End()

func (*GoReq) SetHeaders

func (gr *GoReq) SetHeaders(headers interface{}) *GoReq

SetHeaders is used to set headers with multiple fields. it accepts structs or json strings: for example:

New().Get(ts.URL).
SetHeaders(`{'Content-Type' = 'text/plain','X-Test-Tag'='test'}`).
End()

or

headers := struct {
    ContentType string `json:"Content-Type"`
    XTestTag string `json:"X-Test-Tag"`
} {ContentType:"text/plain",XTestTag:"test"}

New().Get(ts.URL).
SetHeaders(headers).
End()

func (*GoReq) SetLogger

func (gr *GoReq) SetLogger(logger *log.Logger) *GoReq

SetLogger is used to set a Logger

func (*GoReq) Socks5

func (gr *GoReq) Socks5(network, addr string, auth *proxy.Auth, forward proxy.Dialer) *GoReq

Socks5 sets SOCKS5 proxy. For exmaple:

gr.Socks5()"tcp", PROXY_ADDR, nil, proxy.Direct) gr.Socks5("tcp", "127.0.0.1:8080",

&proxy.Auth{User:"username", Password:"password"},
&net.Dialer {
    Timeout: 30 * time.Second,
    KeepAlive: 30 * time.Second,
},

)

func (*GoReq) TLSClientConfig

func (gr *GoReq) TLSClientConfig(config *tls.Config) *GoReq

TLSClientConfig is used to set TLSClientConfig for underling Transport. One example is you can use it to disable security check (https):

goreq.New().TLSClientConfig(&tls.Config{ InsecureSkipVerify: true}).
  Get("https://disable-security-check.com").
  End()

func (*GoReq) Timeout

func (gr *GoReq) Timeout(timeout time.Duration) *GoReq

Timeout is used to set timeout for connections.

type Request

type Request *http.Request

Request represents an HTTP request received by a server or to be sent by a client.

type Response

type Response *http.Response

Response represents the response from an HTTP request.

type RetryConfig

type RetryConfig struct {
	//Max retry count
	RetryCount int
	//Retry timeout
	RetryTimeout int
	// Retry only when received those http status
	RetryOnHTTPStatus []int
}

RetryConfig is used to config retry parameters

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL