yarc

package module
v0.0.0-...-c247f64 Latest Latest
Warning

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

Go to latest
Published: Nov 7, 2017 License: MIT Imports: 14 Imported by: 0

README

YARC

Yet another rest client (for golang)

Yarc is a Go HTTP client library for creating and sending API requests. Check usage or the examples to learn how to yarc into your API client.

Features
  • IMO Nice API
  • Base/Request: Extend Yarc for different endpoints
  • External cache support
  • Native JSON support for sending/receiveng structs
  • Access to http.Request && http.Response
  • Collection of helpers for nice defaults
  • Mock server for integration tests: Yams
  • Stupid Simple cache implementation: Yasci

Install

go get github.com/tinchogob/yarc

Documentation

Read GoDoc

Usage

Yarc uses dave's cheney funcional options pattern There a number of functional option functions to customize each client/request.

The can be applied to Yarc's constructor or to Yarc's request executor.

For example, create a base Yarc client with a host and then extend this client to do a request for method+path.

client, err := Yarc.New(Host("https://api.mercadolibre.com))
if err != nil {
  panic(err)
}

r, err := client.Go(
  GET(),
  Path("/items/1234567"),
)
Query, Headers and on
r, err := client.Go(
  GET(),
  Header("Connection", "keep-alive"),
  Path("/items/1234567"),
  Query("attributes","id,permalink"),
)
Body

While dealing with JSON requests/response APIS, Yarcs provides some nice helpers out of the box.

Posting JSON

Define JSON tagged structs. Use JSON to JSON encode a struct as the Body on requests.

type ItemRequest struct {
    ID     string   `json:"id"`
    Permalink  string   `json:"permalink"`
}

item := ItemRequest{
  ID: "123",
  Permalink: "http://permalink.com",
}

r, err := client.Go(
  POST(),
  Header("Connection", "keep-alive"),
  Path("/items/1234567"),
  Query("attributes","id,permalink"),
  JSON(item),
)

Requests will include an application/json Content-Type header.

ToJSON

Define JSON structs to decode responses. Use ToJSON(body interface{}, errBody interface{}) to decode the response body into body if 2xx or else to errBody.

type Item struct {
    ID     string   `json:"id"`
    Permalink  string   `json:"permalink"`
}

type ApiError struct {
    Message string  `json:"message"`
    Cause string    `json:"cause"`
}

item := Item{}
errB := ApiError{}

r, err := client.Go(
  GET(),
  Header("Connection", "keep-alive"),
  Path("/items/1234567"),
  Query("attributes","id,permalink"),
  ToJSON(&item, &errB),
)

fmt.Println(item, errB)
Accesing to http.Request

Yarcs provides an extension point called With to change/enhance each request

r, err := client.Go(
  GET(),
  Path("/items/1234567"),
  With(func(opts Yarc.Options, req *http.Request) *http.Request {
      return req.WithContext(context.Background())
  })
)

License

MIT License

Documentation

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

func BaseClient

func BaseClient(maxIdleConnsPerHost int, connectionTO time.Duration, requestTO time.Duration) *http.Client

func BaseTrace

func BaseTrace() func(Options) (*httptrace.ClientTrace, error)

func Body

func Body(body []byte) optionFunc

Body sets the request body to the provided []byte There a number of helper functions that simplifies usual cases such as marhsalling a json as the request body see JSON(), XML()

func Client

func Client(client *http.Client) optionFunc

Client lets you use a custom http.Client. By default yarc will use the default http.Client.

func GET

func GET() optionFunc

GET sets the request method to http.MethodGet.

func Header(key string, value string) optionFunc

Header adds name: value to the request headers You should call Header as many times as headers you want to set. Header will preserve previously setted headers.

func Histrix

func Histrix(timeout int, maxConcurrentRequests int, errorPercentThreshold int, client *http.Client) optionFunc

func Host

func Host(host string) optionFunc

Host sets the request host+port to host.

func JSON

func JSON(entity interface{}) optionFunc

JSON sets the request body to the JSON marshall of the provided entity. It also adds "Content-Type: application/json" request header

func POST

func POST() optionFunc

POST sets the request method to http.MethodPost.

func Params

func Params(params ...string) optionFunc

Params sets the replace values for every %s in the request Path. Its intended to be used in conjunction with Path. For example: yarc.Go(Host("/ping/%s"),Params("me")) so yarc ends up calling "/ping/me".

func Path

func Path(path string) optionFunc

Path sets the base path for this request. You should use a generic path with a format string (with %s) so that its generic and can identify all similar requests. Its intended to be used in conjunction with Params. For example: yarc.Go(Host("/ping/%s"),Params("me")) so yarc ends up calling "/ping/me".

func Query

func Query(key string, value string) optionFunc

Query adds key=value queryparam to the request. You should call Query as many time as params you have. They will be concatenated in the same order Query was called. TODO should be safe and sanitize this input

func ToJSON

func ToJSON(body interface{}, errBody interface{}) optionFunc

ToJSON reads the response body and if OK tries to json.Uunmarshall it to body. If not OK tries to json.Uunmarshall it to errBody. It also adds "Accept: application/json" to the request headers.

func Trace

func Trace(trace func(Options) (*httptrace.ClientTrace, error)) optionFunc

Trace lets you build and use an httptrace.ClientTrace for this request. You should use this to gather metrics about each request. You have access to Options so you can group metrics by Method, Host, Path, Etc.

func With

func With(with WithFunc) optionFunc

With adds with to the request's with functions.

func WithCache

func WithCache(c Cache) optionFunc

WithCache will make yarc to use an implementation of yarc.Cache. It MUST be gourutine safe.

Types

type Cache

type Cache interface {
	Get(key *http.Request) (*http.Response, error)
	Set(key *http.Request, response *http.Response) error
}

Cache is Yarc's cache interface. Implementations must be goroutine safe. cache methods will be called for every request, so implementations should define when they want a hit and when they should set. There is an example implementation called yaci

type Options

type Options struct {
	Method  string
	Host    string
	Path    string
	Params  []string
	Query   []string
	ReqBody []byte
	Headers http.Header
	Client  *http.Client
	// contains filtered or unexported fields
}

Yarc options. You shouldn't use this directly but with option functions. Option functions will be applied in order. Each request may set its own option functions that will be applied after builder options and may override or add options.

type WithFunc

type WithFunc func(opts Options, req *http.Request) *http.Request

Provides complete access to the request. You can modify or even return a new request.

func BasicAuth

func BasicAuth(username string, password string) WithFunc

Sets the request basic auth to username and password.

func Context

func Context(ctx context.Context) WithFunc

Runs the request with ctx context.

func Debug

func Debug(out io.Writer) WithFunc

type Yarc

type Yarc struct {
	// contains filtered or unexported fields
}

Yarc is an HTTP request builder and sender

Example
ms, err := yams.New(8181)
if err != nil {
	panic(err)
}

ms.Add(
	yams.Mock{
		Method:     http.MethodPost,
		URL:        "/items/1/ping/2?attributes=id",
		ReqBody:    []byte("{\"id\":\"ping\"}"),
		RespStatus: http.StatusOK,
		RespBody:   []byte("{\"id\":\"pong\"}"),
		Wait:       time.Millisecond * 100,
		Times:      2,
	},
)

yarc, err := New(
	Client(BaseClient(1, time.Second, time.Second)),
	Host("http://127.0.0.1:8181"),
	Path("/items/%s/ping/%s"),
	Header("Connection", "keep-alive"),
	Header("Cache-Control", "no-cache"),
	Trace(BaseTrace()),
	With(Debug(os.Stdout)),
	WithCache(yasci.New(time.Millisecond*100, 100)),
)

if err != nil {
	panic(err)
}

wg := new(sync.WaitGroup)

for i := 0; i < 1; i++ {
	time.Sleep(time.Millisecond * 200)
	wg.Add(1)
	go func() {

		//request body
		body := &struct {
			ID string `json:"id"`
		}{"ping"}

		//response struct to unmarshall response OK
		resp := &struct {
			ID string `json:"id"`
		}{}

		//response struct to unmarshall response NOK
		errBody := &struct {
			ID string `json:"id"`
		}{}

		res, err := yarc.Go(
			POST(),
			Header("X-Name", "Martin"),
			JSON(body),
			Params("1", "2"),
			Query("attributes", "id"),
			With(Context(context.Background())),
			ToJSON(resp, errBody),
		)

		wg.Done()

		if err != nil {
			fmt.Println(err.Error())
			if res != nil {
				fmt.Printf("%d - %s\n", res.StatusCode, errBody.ID)

			}
			return
		}

		fmt.Printf("%d - %s\n", res.StatusCode, resp.ID)

	}()
}

wg.Wait()
ms.Close()
Output:

func New

func New(optsFunc ...optionFunc) (*Yarc, error)

New returns a Yarc builder. Option functions passed here will be applied to each request made with this instance.

func (*Yarc) Go

func (y *Yarc) Go(optsFunc ...optionFunc) (*http.Response, error)

Go builds an *http.Request, applies instance/args options and makes the request. Returns an *http.Response and an Yikes error, if any. Option functions passed here will apply only to this request

type Yikes

type Yikes struct {
	Body interface{}
	// contains filtered or unexported fields
}

Yikes is yarc's error implementation. Since every non 2xx response is considered an error yikes carries the response body if available.

func (Yikes) Error

func (ye Yikes) Error() string

Directories

Path Synopsis

Jump to

Keyboard shortcuts

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