withttp

package module
v0.1.0 Latest Latest
Warning

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

Go to latest
Published: Aug 29, 2022 License: MIT Imports: 9 Imported by: 1

README

withttp

Build http requests and parse their responses with fluent syntax and wit. This package aims to quickly configure http roundtrips by covering common scenarios, while leaving all details of http requests and responses open for the user to allow maximun flexibility.

Supported underlying http implementations are:

  • net/url
  • fasthttp
  • open an issue to include your preferred one!
Query Restful endpoints
var (
  githubApi = withttp.NewEndpoint("GithubAPI").
    Request(withttp.WithURL("https://api.github.com/"))
)

type githubRepoInfo struct {
  ID  int    `json:"id"`
  URL string `json:"html_url"`
}

func GetRepoInfo(user, repo string) (githubRepoInfo, error) {
  call := withttp.NewCall[githubRepoInfo](withttp.NewDefaultFastHttpHttpClientAdapter()).
    WithURI(fmt.Sprintf("repos/%s/%s", user, repo)).
    WithMethod(http.MethodGet).
    WithHeader("User-Agent", "withttp/0.1.0 See https://github.com/sonirico/withttp", false).
    WithHeaderFunc(func() (key, value string, override bool) {
      key = "X-Date"
      value = time.Now().String()
      override = true
      return
    }).
    WithJSON().
    WithExpectedStatusCodes(http.StatusOK)

  err := call.Call(context.Background(), githubApi)

  return call.BodyParsed, err
}

func main() {
  info, _ := GetRepoInfo("sonirico", "withttp")
  log.Println(info)
}
Test your calls again a mock endpoint

Quickly test your calls by creating a mock endpoint

var (
  exchangeListOrders = withttp.NewEndpoint("ListOrders").
        Request(withttp.WithURL("http://example.com")).
        Response(
      withttp.WithResMock(func(res withttp.Response) {
        res.SetBody(io.NopCloser(bytes.NewReader(mockResponse)))
        res.SetStatus(http.StatusOK)
      }),
    )
  mockResponse = []byte(strings.TrimSpace(`
    {"amount": 234, "pair": "BTC/USDT"}
    {"amount": 123, "pair": "ETH/USDT"}`))
)

func main() {
  type Order struct {
    Amount float64 `json:"amount"`
    Pair   string  `json:"pair"`
  }

  res := make(chan Order)

  call := withttp.NewCall[Order](withttp.NewDefaultFastHttpHttpClientAdapter()).
    WithURL("https://github.com/").
    WithMethod(http.MethodGet).
    WithHeader("User-Agent", "withttp/0.1.0 See https://github.com/sonirico/withttp", false).
    WithHeaderFunc(func() (key, value string, override bool) {
      key = "X-Date"
      value = time.Now().String()
      override = true
      return
    }).
    WithJSONEachRowChan(res).
    WithExpectedStatusCodes(http.StatusOK)

  go func() {
    for order := range res {
      log.Println(order)
    }
  }()

  err := call.Call(context.Background(), exchangeListOrders)

  if err != nil {
    panic(err)
  }
}

Documentation

Index

Constants

This section is empty.

Variables

View Source
var (
	ErrAssertion            = errors.New("assertion was unmet")
	ErrUnexpectedStatusCode = errors.Wrap(ErrAssertion, "unexpected status code")
)

Functions

func ConfigureHeader

func ConfigureHeader(req Request, key, value string, override bool) error

func ReadJSON

func ReadJSON[T any](rc io.ReadCloser) (res T, err error)

func ReadStream

func ReadStream[T any](rc io.ReadCloser, factory StreamFactory[T], fn func(T) bool) (err error)

func ReadStreamChan

func ReadStreamChan[T any](rc io.ReadCloser, factory StreamFactory[T], out chan<- T) (err error)

Types

type Call

type Call[T any] struct {
	Req Request
	Res Response

	BodyRaw    []byte
	BodyParsed T

	ReqBodyRaw []byte
	// contains filtered or unexported fields
}

func NewCall

func NewCall[T any](client client) *Call[T]

func (*Call[T]) Call

func (c *Call[T]) Call(ctx context.Context, e *Endpoint) (err error)

func (*Call[T]) Request

func (c *Call[T]) Request(opts ...ReqOption) *Call[T]

func (*Call[T]) Response

func (c *Call[T]) Response(opts ...ResOption) *Call[T]

func (*Call[T]) WithAssert

func (c *Call[T]) WithAssert(fn func(req Response) error) *Call[T]

func (*Call[T]) WithExpectedStatusCodes

func (c *Call[T]) WithExpectedStatusCodes(states ...int) *Call[T]

func (*Call[T]) WithHeader

func (c *Call[T]) WithHeader(key, value string, override bool) *Call[T]

func (*Call[T]) WithHeaderFunc

func (c *Call[T]) WithHeaderFunc(fn func() (key, value string, override bool)) *Call[T]

func (*Call[T]) WithIgnoreBody

func (c *Call[T]) WithIgnoreBody() *Call[T]

func (*Call[T]) WithJSON

func (c *Call[T]) WithJSON() *Call[T]

func (*Call[T]) WithJSONEachRow

func (c *Call[T]) WithJSONEachRow(fn func(T) bool) *Call[T]

func (*Call[T]) WithJSONEachRowChan

func (c *Call[T]) WithJSONEachRowChan(out chan<- T) *Call[T]

func (*Call[T]) WithMethod

func (c *Call[T]) WithMethod(method string) *Call[T]

func (*Call[T]) WithRawBody

func (c *Call[T]) WithRawBody(payload []byte) *Call[T]

func (*Call[T]) WithReadBody

func (c *Call[T]) WithReadBody() *Call[T]

func (*Call[T]) WithStream

func (c *Call[T]) WithStream(factory StreamFactory[T], fn func(T) bool) *Call[T]

func (*Call[T]) WithStreamChan

func (c *Call[T]) WithStreamChan(factory StreamFactory[T], ch chan<- T) *Call[T]

func (*Call[T]) WithURI

func (c *Call[T]) WithURI(raw string) *Call[T]

func (*Call[T]) WithURL

func (c *Call[T]) WithURL(raw string) *Call[T]

type CallResOption

type CallResOption[T any] interface {
	Parse(c *Call[T], r Response) error
}

type CallResOptionFunc

type CallResOptionFunc[T any] func(c *Call[T], res Response) error

func WithAssertion

func WithAssertion[T any](fn func(res Response) error) CallResOptionFunc[T]

func WithCloseBody

func WithCloseBody[T any]() CallResOptionFunc[T]

func WithExpectedStatusCodes

func WithExpectedStatusCodes[T any](states ...int) CallResOptionFunc[T]

func WithIgnoredBody

func WithIgnoredBody[T any]() CallResOptionFunc[T]

func WithJSON

func WithJSON[T any]() CallResOptionFunc[T]

func WithRawBody

func WithRawBody[T any]() CallResOptionFunc[T]

func WithStream

func WithStream[T any](factory StreamFactory[T], fn func(T) bool) CallResOptionFunc[T]

func WithStreamChan

func WithStreamChan[T any](factory StreamFactory[T], out chan<- T) CallResOptionFunc[T]

func (CallResOptionFunc[T]) Parse

func (f CallResOptionFunc[T]) Parse(c *Call[T], res Response) error

type Endpoint

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

func NewEndpoint

func NewEndpoint(name string) *Endpoint

func (*Endpoint) Request

func (e *Endpoint) Request(opts ...ReqOption) *Endpoint

func (*Endpoint) Response

func (e *Endpoint) Response(opts ...ResOption) *Endpoint

type FastHttpHttpClientAdapter

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

func NewDefaultFastHttpHttpClientAdapter

func NewDefaultFastHttpHttpClientAdapter() *FastHttpHttpClientAdapter

func NewFastHttpHttpClientAdapter

func NewFastHttpHttpClientAdapter(cli *fasthttp.Client) *FastHttpHttpClientAdapter

func (*FastHttpHttpClientAdapter) Do

func (*FastHttpHttpClientAdapter) Request

func (a *FastHttpHttpClientAdapter) Request() (Request, error)

type JSONEachRowStream

type JSONEachRowStream[T any] struct {
	// contains filtered or unexported fields
}

func (*JSONEachRowStream[T]) Data

func (s *JSONEachRowStream[T]) Data() T

func (*JSONEachRowStream[T]) Err

func (s *JSONEachRowStream[T]) Err() error

func (*JSONEachRowStream[T]) Next

func (s *JSONEachRowStream[T]) Next(_ context.Context) bool

type MockEndpoint

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

type MockHttpClientAdapter

type MockHttpClientAdapter struct{}

func NewMockHttpClientAdapter

func NewMockHttpClientAdapter() *MockHttpClientAdapter

func (*MockHttpClientAdapter) Do

func (*MockHttpClientAdapter) Request

func (a *MockHttpClientAdapter) Request() (Request, error)

type NativeHttpClientAdapter

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

func NewDefaultNativeHttpClientAdapter

func NewDefaultNativeHttpClientAdapter() *NativeHttpClientAdapter

func NewNativeHttpClientAdapter

func NewNativeHttpClientAdapter(cli *http.Client) *NativeHttpClientAdapter

func (*NativeHttpClientAdapter) Do

func (*NativeHttpClientAdapter) Request

func (a *NativeHttpClientAdapter) Request() (Request, error)

type ReqOption

type ReqOption interface {
	Configure(r Request) error
}

func WithURI

func WithURI(raw string) ReqOption

func WithURL

func WithURL(raw string) ReqOption

type ReqOptionFunc

type ReqOptionFunc func(req Request) error

func (ReqOptionFunc) Configure

func (f ReqOptionFunc) Configure(req Request) error

type Request

type Request interface {
	SetMethod(string)
	SetHeader(k, v string)
	AddHeader(k, v string)
	SetURL(*url.URL)
	SetBody(rc io.ReadCloser)

	URL() *url.URL
}

type ResOption

type ResOption interface {
	Parse(r Response) error
}

func WithResMock

func WithResMock(fn func(response Response)) ResOption

type ResOptionFunc

type ResOptionFunc func(res Response) error

func (ResOptionFunc) Parse

func (f ResOptionFunc) Parse(res Response) error

type Response

type Response interface {
	Status() int
	StatusText() string
	Body() io.ReadCloser

	SetBody(rc io.ReadCloser)
	SetStatus(status int)
}

type Stream

type Stream[T any] interface {
	Next(ctx context.Context) bool
	Data() T
	Err() error
}

func NewJSONEachRowStream

func NewJSONEachRowStream[T any](r io.Reader) Stream[T]

type StreamFactory

type StreamFactory[T any] interface {
	Get(r io.Reader) Stream[T]
}

func NewJSONEachRowStreamFactory

func NewJSONEachRowStreamFactory[T any]() StreamFactory[T]

type StreamFactoryFunc

type StreamFactoryFunc[T any] func(reader io.Reader) Stream[T]

func (StreamFactoryFunc[T]) Get

func (f StreamFactoryFunc[T]) Get(r io.Reader) Stream[T]

Directories

Path Synopsis
examples
fasthttp command
mock command

Jump to

Keyboard shortcuts

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