withttp

package module
v0.9.0 Latest Latest
Warning

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

Go to latest
Published: Jul 3, 2025 License: MIT Imports: 19 Imported by: 1

README ΒΆ

🎯 withttp

Build HTTP requests and parse responses with fluent syntax and wit

Build Status Go Report Card GoDoc Go Version

A fluent HTTP client library that covers common scenarios while maintaining maximum flexibility


πŸš€ Features

  • πŸ”„ Fluent API - Chain methods for intuitive request building
  • πŸ“‘ Multiple HTTP Backends - Support for net/http and fasthttp
  • 🎯 Type-Safe Responses - Generic-based response parsing
  • πŸ“Š Streaming Support - Stream data from slices, channels, or readers
  • πŸ§ͺ Mock-Friendly - Built-in mocking capabilities for testing
  • ⚑ High Performance - Optimized for speed and low allocations

πŸ“¦ Installation

go get github.com/sonirico/withttp

πŸŽ›οΈ Supported HTTP Implementations

Implementation Description
net/http Go's standard HTTP client
fasthttp High-performance HTTP client
Custom Client Implement the Client interface

πŸ’‘ Missing your preferred HTTP client? Open an issue and let us know!

πŸ“š Table of Contents

🏁 Quick Start

package main

import (
    "context"
    "fmt"
    "net/http"
    
    "github.com/sonirico/withttp"
)

type GithubRepo struct {
    ID   int    `json:"id"`
    Name string `json:"name"`
    URL  string `json:"html_url"`
}

func main() {
    call := withttp.NewCall[GithubRepo](withttp.Fasthttp()).
        URL("https://api.github.com/repos/sonirico/withttp").
        Method(http.MethodGet).
        Header("User-Agent", "withttp-example/1.0", false).
        ParseJSON().
        ExpectedStatusCodes(http.StatusOK)

    err := call.Call(context.Background())
    if err != nil {
        panic(err)
    }

    fmt.Printf("Repository: %s (ID: %d)\n", call.BodyParsed.Name, call.BodyParsed.ID)
}

πŸ’‘ Examples

All examples are now available as:

  • Example functions in the test files - you can run these with go test -v -run "^Example"
  • Test functions for comprehensive testing scenarios
  • Documentation examples in the code itself
RESTful API Queries
Click to expand
type GithubRepoInfo struct {
  ID  int    `json:"id"`
  URL string `json:"html_url"`
}

func GetRepoInfo(user, repo string) (GithubRepoInfo, error) {
  call := withttp.NewCall[GithubRepoInfo](withttp.Fasthttp()).
    URL(fmt.Sprintf("https://api.github.com/repos/%s/%s", user, repo)).
    Method(http.MethodGet).
    Header("User-Agent", "withttp/0.5.1 See https://github.com/sonirico/withttp", false).
    ParseJSON().
    ExpectedStatusCodes(http.StatusOK)

  err := call.Call(context.Background())
  return call.BodyParsed, err
}

func main() {
  info, _ := GetRepoInfo("sonirico", "withttp")
  log.Println(info)
}
Streaming Data
πŸ“„ Stream from Slice
View example

See test example

type metric struct {
  Time time.Time `json:"t"`
  Temp float32   `json:"T"`
}

func CreateStream() error {
  points := []metric{
    {Time: time.Unix(time.Now().Unix()-1, 0), Temp: 39},
    {Time: time.Now(), Temp: 40},
  }

  stream := withttp.Slice[metric](points)
  testEndpoint := withttp.NewEndpoint("webhook-site-request-stream-example").
    Request(withttp.BaseURL("https://webhook.site/24e84e8f-75cf-4239-828e-8bed244c0afb"))

  call := withttp.NewCall[any](withttp.Fasthttp()).
    Method(http.MethodPost).
    ContentType(withttp.ContentTypeJSONEachRow).
    RequestSniffed(func(data []byte, err error) {
      fmt.Printf("recv: '%s', err: %v", string(data), err)
    }).
    RequestStreamBody(withttp.RequestStreamBody[any, metric](stream)).
    ExpectedStatusCodes(http.StatusOK)

  return call.CallEndpoint(context.Background(), testEndpoint)
}
πŸ“‘ Stream from Channel
View example

See test example

func CreateStreamChannel() error {
  points := make(chan metric, 2)

  go func() {
    points <- metric{Time: time.Unix(time.Now().Unix()-1, 0), Temp: 39}
    points <- metric{Time: time.Now(), Temp: 40}
    close(points)
  }()

  stream := withttp.Channel[metric](points)
  testEndpoint := withttp.NewEndpoint("webhook-site-request-stream-example").
    Request(withttp.BaseURL("https://webhook.site/24e84e8f-75cf-4239-828e-8bed244c0afb"))

  call := withttp.NewCall[any](withttp.Fasthttp()).
    Method(http.MethodPost).
    ContentType(withttp.ContentTypeJSONEachRow).
    RequestSniffed(func(data []byte, err error) {
      fmt.Printf("recv: '%s', err: %v", string(data), err)
    }).
    RequestStreamBody(withttp.RequestStreamBody[any, metric](stream)).
    ExpectedStatusCodes(http.StatusOK)

  return call.CallEndpoint(context.Background(), testEndpoint)
}
πŸ“– Stream from Reader
View example

See test example

func CreateStreamReader() error {
  buf := bytes.NewBuffer(nil)

  go func() {
    buf.WriteString("{\"t\":\"2022-09-01T00:58:15+02:00\"")
    buf.WriteString(",\"T\":39}\n{\"t\":\"2022-09-01T00:59:15+02:00\",\"T\":40}\n")
  }()

  streamFactory := withttp.NewProxyStreamFactory(1 << 10)
  stream := withttp.NewStreamFromReader(buf, streamFactory)
  testEndpoint := withttp.NewEndpoint("webhook-site-request-stream-example").
    Request(withttp.BaseURL("https://webhook.site/24e84e8f-75cf-4239-828e-8bed244c0afb"))

  call := withttp.NewCall[any](withttp.NetHttp()).
    Method(http.MethodPost).
    RequestSniffed(func(data []byte, err error) {
      fmt.Printf("recv: '%s', err: %v", string(data), err)
    }).
    ContentType(withttp.ContentTypeJSONEachRow).
    RequestStreamBody(withttp.RequestStreamBody[any, []byte](stream)).
    ExpectedStatusCodes(http.StatusOK)

  return call.CallEndpoint(context.Background(), testEndpoint)
}
Multiple Endpoints
Click to expand

Define reusable endpoint configurations for API consistency:

var (
  githubApi = withttp.NewEndpoint("GithubAPI").
    Request(withttp.BaseURL("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.Fasthttp()).
    URI(fmt.Sprintf("repos/%s/%s", user, repo)).
    Method(http.MethodGet).
    Header("User-Agent", "withttp/0.5.1 See https://github.com/sonirico/withttp", false).
    HeaderFunc(func() (key, value string, override bool) {
      return "X-Date", time.Now().String(), true
    }).
    ParseJSON().
    ExpectedStatusCodes(http.StatusOK)

  err := call.CallEndpoint(context.Background(), githubApi)
  return call.BodyParsed, err
}

type GithubCreateIssueResponse struct {
  ID  int    `json:"id"`
  URL string `json:"url"`
}

func CreateRepoIssue(user, repo, title, body, assignee string) (GithubCreateIssueResponse, error) {
  type payload struct {
    Title    string `json:"title"`
    Body     string `json:"body"`
    Assignee string `json:"assignee"`
  }

  p := payload{Title: title, Body: body, Assignee: assignee}

  call := withttp.NewCall[GithubCreateIssueResponse](withttp.Fasthttp()).
    URI(fmt.Sprintf("repos/%s/%s/issues", user, repo)).
    Method(http.MethodPost).
    ContentType("application/vnd+github+json").
    Body(p).
    HeaderFunc(func() (key, value string, override bool) {
      return "Authorization", fmt.Sprintf("Bearer %s", "S3cret"), true
    }).
    ExpectedStatusCodes(http.StatusCreated)

  err := call.CallEndpoint(context.Background(), githubApi)
  log.Println("req body", string(call.Req.Body()))

  return call.BodyParsed, err
}

func main() {
  // Fetch repo info
  info, _ := GetRepoInfo("sonirico", "withttp")
  log.Println(info)

  // Create an issue
  res, err := CreateRepoIssue("sonirico", "withttp", "test", "This is a test", "sonirico")
  log.Println(res, err)
}
Testing with Mocks
Click to expand

Easily test your HTTP calls with built-in mocking:

var (
  exchangeListOrders = withttp.NewEndpoint("ListOrders").
    Request(withttp.BaseURL("http://example.com")).
    Response(
      withttp.MockedRes(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.Fasthttp()).
    URL("https://github.com/").
    Method(http.MethodGet).
    Header("User-Agent", "withttp/0.5.1 See https://github.com/sonirico/withttp", false).
    ParseJSONEachRowChan(res).
    ExpectedStatusCodes(http.StatusOK)

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

  err := call.CallEndpoint(context.Background(), exchangeListOrders)
  if err != nil {
    panic(err)
  }
}

πŸ—ΊοΈ Roadmap

Feature Status
Form-data content type codecs πŸ”„ In Progress
Enhanced auth methods πŸ“‹ Planned
XML parsing support πŸ“‹ Planned
Tabular data support πŸ“‹ Planned
gRPC integration πŸ€” Considering

🀝 Contributing

We welcome contributions! Please see our Contributing Guide for details.

  1. Fork the repository
  2. Create your feature branch (git checkout -b feature/amazing-feature)
  3. Commit your changes (git commit -m 'Add some amazing feature')
  4. Push to the branch (git push origin feature/amazing-feature)
  5. Open a Pull Request

πŸ“„ License

This project is licensed under the MIT License - see the LICENSE file for details.

⭐ Show Your Support

If this project helped you, please give it a ⭐! It helps others discover the project.


Documentation β€’ Test Examples β€’ Issues β€’ Discussions

Made with ❀️ by sonirico

Documentation ΒΆ

Overview ΒΆ

Example (Fasthttp_basicCall) ΒΆ

Example_fasthttp_basicCall demonstrates how to make a simple HTTP call using the FastHTTP adapter.

type RepoInfo struct {
	ID   int    `json:"id"`
	Name string `json:"name"`
}

// Create a mocked endpoint for the example
endpoint := NewEndpoint("GithubAPI").
	Request(BaseURL("https://api.github.com")).
	Response(
		MockedRes(func(res Response) {
			res.SetBody(io.NopCloser(strings.NewReader(`{"id": 12345, "name": "withttp"}`)))
			res.SetStatus(http.StatusOK)
		}),
	)

call := NewCall[RepoInfo](NewMockHttpClientAdapter()).
	URI("/repos/user/repo").
	Method(http.MethodGet).
	Header("User-Agent", "withttp-example", false).
	ParseJSON().
	ExpectedStatusCodes(http.StatusOK)

err := call.CallEndpoint(context.Background(), endpoint)
if err != nil {
	fmt.Printf("Error: %v\n", err)
	return
}

fmt.Printf("Repo ID: %d, Name: %s\n", call.BodyParsed.ID, call.BodyParsed.Name)
Output:
Repo ID: 12345, Name: withttp
Example (Fasthttp_postRequest) ΒΆ

Example_fasthttp_postRequest demonstrates how to make a POST request with JSON body using FastHTTP.

type CreateRequest struct {
	Title string `json:"title"`
	Body  string `json:"body"`
}

type CreateResponse struct {
	ID  int    `json:"id"`
	URL string `json:"url"`
}

// Create a mocked endpoint for the example
endpoint := NewEndpoint("API").
	Request(BaseURL("https://api.example.com")).
	Response(
		MockedRes(func(res Response) {
			res.SetBody(
				io.NopCloser(
					strings.NewReader(`{"id": 42, "url": "https://api.example.com/items/42"}`),
				),
			)
			res.SetStatus(http.StatusCreated)
		}),
	)

payload := CreateRequest{
	Title: "Example Item",
	Body:  "This is an example",
}

call := NewCall[CreateResponse](NewMockHttpClientAdapter()).
	URI("/items").
	Method(http.MethodPost).
	ContentType(ContentTypeJSON).
	Body(payload).
	Header("Authorization", "Bearer token", true).
	ParseJSON().
	ExpectedStatusCodes(http.StatusCreated)

err := call.CallEndpoint(context.Background(), endpoint)
if err != nil {
	fmt.Printf("Error: %v\n", err)
	return
}

fmt.Printf("Created item ID: %d\n", call.BodyParsed.ID)
Output:
Created item ID: 42
Example (Fasthttp_withHeaderFunc) ΒΆ

Example_fasthttp_withHeaderFunc demonstrates using header functions with FastHTTP.

type APIResponse struct {
	Message string `json:"message"`
}

endpoint := NewEndpoint("API").
	Request(BaseURL("https://api.example.com")).
	Response(
		MockedRes(func(res Response) {
			res.SetBody(io.NopCloser(strings.NewReader(`{"message": "Hello"}`)))
			res.SetStatus(http.StatusOK)
		}),
	)

call := NewCall[APIResponse](NewMockHttpClientAdapter()).
	URI("/hello").
	Method(http.MethodGet).
	HeaderFunc(func() (key, value string, override bool) {
		key = "X-Timestamp"
		value = "2025-06-29T12:00:00Z"
		override = true
		return
	}).
	HeaderFunc(func() (key, value string, override bool) {
		key = "X-Request-ID"
		value = "req-12345"
		override = true
		return
	}).
	ParseJSON().
	ExpectedStatusCodes(http.StatusOK)

err := call.CallEndpoint(context.Background(), endpoint)
if err != nil {
	fmt.Printf("Error: %v\n", err)
	return
}

fmt.Printf("Response: %s\n", call.BodyParsed.Message)
Output:
Response: Hello
Example (MockEndpoint) ΒΆ

Example_mockEndpoint demonstrates how to create and use a mocked endpoint for testing.

type Order struct {
	Amount float64 `json:"amount"`
	Pair   string  `json:"pair"`
}

// Create a mocked endpoint that returns test data
mockEndpoint := NewEndpoint("MockExchange").
	Request(BaseURL("http://example.com")).
	Response(
		MockedRes(func(res Response) {
			res.SetBody(io.NopCloser(strings.NewReader(`{"amount": 100.5, "pair": "BTC/USD"}`)))
			res.SetStatus(http.StatusOK)
		}),
	)

call := NewCall[Order](NewMockHttpClientAdapter()).
	Method(http.MethodGet).
	Header("Authorization", "Bearer token123", true).
	ParseJSON().
	ExpectedStatusCodes(http.StatusOK)

err := call.CallEndpoint(context.Background(), mockEndpoint)
if err != nil {
	fmt.Printf("Error: %v\n", err)
	return
}

fmt.Printf("Order amount: %.1f, Pair: %s\n", call.BodyParsed.Amount, call.BodyParsed.Pair)
Output:
Order amount: 100.5, Pair: BTC/USD
Example (ParseCSV) ΒΆ

Example_parseCSV demonstrates parsing CSV response data.

type Repository struct {
	Rank  int
	Name  string
	Stars int
}

csvData := `rank,name,stars
1,awesome-go,75000
2,gin,65000`

endpoint := NewEndpoint("RepoStats").
	Request(BaseURL("https://api.example.com")).
	Response(
		MockedRes(func(res Response) {
			res.SetBody(io.NopCloser(strings.NewReader(csvData)))
			res.SetStatus(http.StatusOK)
		}),
	)

parser := csvparser.New[Repository](
	csvparser.SeparatorComma,
	csvparser.IntCol[Repository](
		csvparser.QuoteNone,
		nil,
		func(x *Repository, rank int) { x.Rank = rank },
	),
	csvparser.StringCol[Repository](
		csvparser.QuoteNone,
		nil,
		func(x *Repository, name string) { x.Name = name },
	),
	csvparser.IntCol[Repository](
		csvparser.QuoteNone,
		nil,
		func(x *Repository, stars int) { x.Stars = stars },
	),
)

call := NewCall[Repository](NewMockHttpClientAdapter()).
	URI("/top-repos.csv").
	Method(http.MethodGet).
	ParseCSV(1, parser, func(repo Repository) bool { // skip 1 header line
		fmt.Printf("Rank %d: %s (%d stars)\n", repo.Rank, repo.Name, repo.Stars)
		return true // continue processing
	}).
	ExpectedStatusCodes(http.StatusOK)

err := call.CallEndpoint(context.Background(), endpoint)
if err != nil {
	fmt.Printf("Error: %v\n", err)
	return
}
Output:
Rank 1: awesome-go (75000 stars)
Rank 2: gin (65000 stars)
Example (ParseJSONEachRow) ΒΆ

Example_parseJSONEachRow demonstrates parsing JSON-each-row format responses.

type Trade struct {
	Price  float64 `json:"price"`
	Volume float64 `json:"volume"`
}

mockData := `{"price": 50000.0, "volume": 1.5}
{"price": 51000.0, "volume": 0.8}`

mockEndpoint := NewEndpoint("TradesAPI").
	Request(BaseURL("http://example.com")).
	Response(
		MockedRes(func(res Response) {
			res.SetBody(io.NopCloser(strings.NewReader(mockData)))
			res.SetStatus(http.StatusOK)
		}),
	)

var trades []Trade
call := NewCall[Trade](NewMockHttpClientAdapter()).
	Method(http.MethodGet).
	ParseJSONEachRow(func(trade Trade) bool {
		trades = append(trades, trade)
		return true // continue processing
	}).
	ExpectedStatusCodes(http.StatusOK)

err := call.CallEndpoint(context.Background(), mockEndpoint)
if err != nil {
	fmt.Printf("Error: %v\n", err)
	return
}

fmt.Printf("Processed %d trades\n", len(trades))
if len(trades) > 0 {
	fmt.Printf("First trade: $%.0f, volume: %.1f\n", trades[0].Price, trades[0].Volume)
}
Output:
Processed 2 trades
First trade: $50000, volume: 1.5
Example (RequestStream_fromSlice) ΒΆ

Example_requestStream_fromSlice demonstrates streaming data from a slice to the server.

type DataPoint struct {
	Timestamp int64   `json:"ts"`
	Value     float64 `json:"val"`
}

// Sample data to stream
data := []DataPoint{
	{Timestamp: 1672531200, Value: 25.5},
	{Timestamp: 1672531260, Value: 26.1},
	{Timestamp: 1672531320, Value: 24.8},
}

stream := Slice[DataPoint](data)

mockEndpoint := NewEndpoint("DataIngestion").
	Request(BaseURL("https://api.example.com")).
	Response(
		MockedRes(func(res Response) {
			res.SetBody(io.NopCloser(strings.NewReader(`{"status": "received"}`)))
			res.SetStatus(http.StatusOK)
		}),
	)

call := NewCall[any](NewMockHttpClientAdapter()).
	URI("/data").
	Method(http.MethodPost).
	ContentType(ContentTypeJSONEachRow).
	RequestStreamBody(
		RequestStreamBody[any, DataPoint](stream),
	).
	ExpectedStatusCodes(http.StatusOK)

err := call.CallEndpoint(context.Background(), mockEndpoint)
if err != nil {
	fmt.Printf("Error: %v\n", err)
	return
}

fmt.Println("Data streamed successfully")
Output:
Data streamed successfully
Example (RequestStream_withSniffer) ΒΆ

Example_requestStream_withSniffer demonstrates streaming with request sniffing.

type Event struct {
	Type string `json:"type"`
}

events := []Event{
	{Type: "click"},
	{Type: "view"},
}

stream := Slice[Event](events)

mockEndpoint := NewEndpoint("Analytics").
	Request(BaseURL("https://api.example.com")).
	Response(
		MockedRes(func(res Response) {
			res.SetBody(io.NopCloser(strings.NewReader(`{"processed": true}`)))
			res.SetStatus(http.StatusOK)
		}),
	)

call := NewCall[any](NewMockHttpClientAdapter()).
	URI("/events").
	Method(http.MethodPost).
	ContentType(ContentTypeJSONEachRow).
	RequestSniffed(func(data []byte, err error) {
		if err == nil {
			// Simplify output to avoid JSON formatting issues
			if strings.Contains(string(data), "click") {
				fmt.Println("Sending click event")
			} else if strings.Contains(string(data), "view") {
				fmt.Println("Sending view event")
			}
		}
	}).
	RequestStreamBody(
		RequestStreamBody[any, Event](stream),
	).
	ExpectedStatusCodes(http.StatusOK)

err := call.CallEndpoint(context.Background(), mockEndpoint)
if err != nil {
	fmt.Printf("Error: %v\n", err)
	return
}

fmt.Println("Events processed")
Output:
Sending click event
Sending view event
Events processed
Example (SingleCall) ΒΆ

Example_singleCall demonstrates making a simple HTTP GET request.

type RepoInfo struct {
	ID   int    `json:"id"`
	Name string `json:"name"`
}

// Create a mocked endpoint for the example
endpoint := NewEndpoint("GithubAPI").
	Request(BaseURL("https://api.github.com")).
	Response(
		MockedRes(func(res Response) {
			res.SetBody(io.NopCloser(strings.NewReader(`{"id": 12345, "name": "withttp"}`)))
			res.SetStatus(http.StatusOK)
		}),
	)

call := NewCall[RepoInfo](NewMockHttpClientAdapter()).
	URI("/repos/user/repo").
	Method(http.MethodGet).
	Header("User-Agent", "withttp-example", false).
	ParseJSON().
	ExpectedStatusCodes(http.StatusOK)

err := call.CallEndpoint(context.Background(), endpoint)
if err != nil {
	fmt.Printf("Error: %v\n", err)
	return
}

fmt.Printf("Repo ID: %d, Name: %s\n", call.BodyParsed.ID, call.BodyParsed.Name)
Output:
Repo ID: 12345, Name: withttp
Example (SingleCall_directURL) ΒΆ

Example_singleCall_directURL demonstrates making a request directly to a URL without an endpoint.

type SimpleResponse struct {
	Status string `json:"status"`
}

// For this example, we'll simulate a call but skip it in practice
// In real usage, you would just call without the skip
call := NewCall[SimpleResponse](NetHttp()).
	URL("https://httpbin.org/json").
	Method(http.MethodGet).
	Header("User-Agent", "withttp-example", false).
	ParseJSON().
	ExpectedStatusCodes(http.StatusOK)

// For documentation purposes, we'll show what the call would look like
_ = call // Normally: err := call.Call(context.Background())

fmt.Println("This would make a direct HTTP call to the specified URL")
Output:
This would make a direct HTTP call to the specified URL

Index ΒΆ

Examples ΒΆ

Constants ΒΆ

This section is empty.

Variables ΒΆ

View Source
var (
	ContentTypeJSON        string = "application/json"
	ContentTypeJSONEachRow string = "application/jsoneachrow"
)
View Source
var (
	ErrAssertion            = errors.New("assertion was unmet")
	ErrUnexpectedStatusCode = errors.Wrap(ErrAssertion, "unexpected status code")
	ErrInsufficientParams   = errors.New("insufficient params")
)
View Source
var (
	ErrUnknownContentType = errors.New("unknown content type")
)

Functions ΒΆ

func B2S ΒΆ added in v0.5.0

func B2S(data []byte) string

func BtsIsset ΒΆ added in v0.2.0

func BtsIsset(bts []byte) bool

func BytesEquals ΒΆ added in v0.3.0

func BytesEquals(a, b []byte) bool

func ConfigureHeader ΒΆ

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

func ContentTypeCodec ΒΆ added in v0.8.0

func ContentTypeCodec(c string) (codec.Codec, error)

func CreateAuthorizationHeader ΒΆ added in v0.5.0

func CreateAuthorizationHeader(kind authHeaderKind, user, pass string) (string, error)

func EncodeBody ΒΆ added in v0.2.0

func EncodeBody(payload any, contentType string) (bts []byte, err error)

func EncodeStream ΒΆ added in v0.3.0

func EncodeStream[T any](
	ctx context.Context,
	r rangeable[T],
	req Request,
	encoder codec.Encoder,
	sniffer func([]byte, error),
) (err 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)

func S2B ΒΆ added in v0.5.0

func S2B(s string) []byte

func StrIsset ΒΆ added in v0.2.0

func StrIsset(s string) bool

Types ΒΆ

type CSVStream ΒΆ added in v0.6.0

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

func (*CSVStream[T]) Data ΒΆ added in v0.6.0

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

func (*CSVStream[T]) Err ΒΆ added in v0.6.0

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

func (*CSVStream[T]) Next ΒΆ added in v0.6.0

func (s *CSVStream[T]) Next(ctx context.Context) bool

type Call ΒΆ

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

	BodyRaw    []byte
	BodyParsed T

	ReqContentType string
	ReqBodyRaw     []byte
	ReqIsStream    bool

	ReqStreamWriter  func(ctx context.Context, c *Call[T], res Request, wg *sync.WaitGroup) error
	ReqStreamSniffer func([]byte, error)
	ReqShouldSniff   bool
	// contains filtered or unexported fields
}

func NewCall ΒΆ

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

func (*Call[T]) Assert ΒΆ added in v0.8.0

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

func (*Call[T]) BasicAuth ΒΆ added in v0.8.0

func (c *Call[T]) BasicAuth(user, pass string) *Call[T]

func (*Call[T]) Body ΒΆ added in v0.8.0

func (c *Call[T]) Body(payload any) *Call[T]

func (*Call[T]) BodyStream ΒΆ added in v0.8.0

func (c *Call[T]) BodyStream(rc io.ReadWriteCloser, bodySize int) *Call[T]

BodyStream receives a stream of data to set on the request. Second parameter `bodySize` indicates the estimated content-length of this stream. Required when employing fasthttp http client.

func (*Call[T]) Call ΒΆ

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

func (*Call[T]) CallEndpoint ΒΆ added in v0.2.0

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

func (*Call[T]) ContentLength ΒΆ added in v0.8.0

func (c *Call[T]) ContentLength(length int) *Call[T]

func (*Call[T]) ContentType ΒΆ added in v0.8.0

func (c *Call[T]) ContentType(ct string) *Call[T]

func (*Call[T]) ExpectedStatusCodes ΒΆ added in v0.8.0

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

func (*Call[T]) Header ΒΆ added in v0.8.0

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

func (*Call[T]) HeaderFunc ΒΆ added in v0.8.0

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

func (*Call[T]) IgnoreResponseBody ΒΆ added in v0.8.0

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

func (*Call[T]) Log ΒΆ added in v0.7.0

func (c *Call[T]) Log(w io.Writer)

func (*Call[T]) Method ΒΆ added in v0.8.0

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

func (*Call[T]) ParseCSV ΒΆ added in v0.8.0

func (c *Call[T]) ParseCSV(
	ignoreLines int,
	parser csvparser.Parser[T],
	fn func(T) bool,
) *Call[T]

func (*Call[T]) ParseJSON ΒΆ added in v0.8.0

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

func (*Call[T]) ParseJSONEachRow ΒΆ added in v0.8.0

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

func (*Call[T]) ParseJSONEachRowChan ΒΆ added in v0.8.0

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

func (*Call[T]) ParseStream ΒΆ added in v0.8.0

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

func (*Call[T]) ParseStreamChan ΒΆ added in v0.8.0

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

func (*Call[T]) Query ΒΆ added in v0.9.0

func (c *Call[T]) Query(k, v string) *Call[T]

func (*Call[T]) RawBody ΒΆ added in v0.8.0

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

func (*Call[T]) ReadBody ΒΆ added in v0.8.0

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

func (*Call[T]) Request ΒΆ

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

func (*Call[T]) RequestSniffed ΒΆ added in v0.8.0

func (c *Call[T]) RequestSniffed(fn func([]byte, error)) *Call[T]

func (*Call[T]) RequestStreamBody ΒΆ added in v0.8.0

func (c *Call[T]) RequestStreamBody(opt StreamCallReqOptionFunc[T]) *Call[T]

func (*Call[T]) Response ΒΆ

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

func (*Call[T]) URI ΒΆ added in v0.8.0

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

func (*Call[T]) URL ΒΆ added in v0.8.0

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

func (*Call[T]) WithLogger ΒΆ added in v0.7.0

func (c *Call[T]) WithLogger(l logger) *Call[T]

type CallReqOption ΒΆ added in v0.3.0

type CallReqOption[T any] interface {
	Configure(c *Call[T], r Request) error
}

type CallReqOptionFunc ΒΆ added in v0.2.0

type CallReqOptionFunc[T any] func(c *Call[T], res Request) error

func BasicAuth ΒΆ added in v0.8.0

func BasicAuth[T any](user, pass string) CallReqOptionFunc[T]

func Body ΒΆ added in v0.8.0

func Body[T any](payload any) CallReqOptionFunc[T]

func BodyStream ΒΆ added in v0.8.0

func BodyStream[T any](rc io.ReadWriteCloser, bodySize int) CallReqOptionFunc[T]

func ContentType ΒΆ added in v0.2.0

func ContentType[T any](ct string) CallReqOptionFunc[T]
func Header[T any](k, v string, override bool) CallReqOptionFunc[T]

func HeaderFunc ΒΆ added in v0.8.0

func HeaderFunc[T any](fn func() (string, string, bool)) CallReqOptionFunc[T]

func Method ΒΆ added in v0.8.0

func Method[T any](method string) CallReqOptionFunc[T]

func Query ΒΆ added in v0.9.0

func Query[T any](k, v string) CallReqOptionFunc[T]

func RawBody ΒΆ added in v0.8.0

func RawBody[T any](payload []byte) CallReqOptionFunc[T]

func RequestSniffer ΒΆ added in v0.8.0

func RequestSniffer[T any](fn func([]byte, error)) CallReqOptionFunc[T]

func URI ΒΆ added in v0.8.0

func URI[T any](raw string) CallReqOptionFunc[T]

func URL ΒΆ added in v0.8.0

func URL[T any](raw string) CallReqOptionFunc[T]

func (CallReqOptionFunc[T]) Configure ΒΆ added in v0.2.0

func (f CallReqOptionFunc[T]) Configure(c *Call[T], req Request) error

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 Assertion ΒΆ added in v0.8.0

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

func CloseBody ΒΆ added in v0.8.0

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

func ExpectedStatusCodes ΒΆ added in v0.8.0

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

func IgnoredBody ΒΆ added in v0.8.0

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

func ParseBodyRaw ΒΆ added in v0.8.0

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

func ParseJSON ΒΆ added in v0.8.0

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

func ParseStream ΒΆ added in v0.8.0

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

func ParseStreamChan ΒΆ added in v0.8.0

func ParseStreamChan[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 Channel ΒΆ added in v0.4.0

type Channel[T any] chan T

func (Channel[T]) Range ΒΆ added in v0.4.0

func (c Channel[T]) Range(fn func(int, T) bool)

func (Channel[T]) Serialize ΒΆ added in v0.4.0

func (c Channel[T]) Serialize() bool

type Client ΒΆ added in v0.7.0

type Client interface {
	Request(ctx context.Context) (Request, error)
	Do(ctx context.Context, req Request) (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 Fasthttp ΒΆ added in v0.8.0

func Fasthttp() *FastHttpHttpClientAdapter

func FasthttpClient ΒΆ added in v0.8.0

func FasthttpClient(cli *fasthttp.Client) *FastHttpHttpClientAdapter

func (*FastHttpHttpClientAdapter) Do ΒΆ

func (*FastHttpHttpClientAdapter) Request ΒΆ

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(ctx context.Context) bool

type MockEndpoint ΒΆ

type MockEndpoint struct{}

type MockHttpClientAdapter ΒΆ

type MockHttpClientAdapter struct{}

func NewMockHttpClientAdapter ΒΆ

func NewMockHttpClientAdapter() *MockHttpClientAdapter

func (*MockHttpClientAdapter) Do ΒΆ

func (*MockHttpClientAdapter) Request ΒΆ

type NativeHttpClientAdapter ΒΆ

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

func NetHttp ΒΆ added in v0.8.0

func NetHttp() *NativeHttpClientAdapter

func NetHttpClient ΒΆ added in v0.8.0

func NetHttpClient(cli *http.Client) *NativeHttpClientAdapter

func (*NativeHttpClientAdapter) Do ΒΆ

func (*NativeHttpClientAdapter) Request ΒΆ

type NewLineStream ΒΆ added in v0.4.0

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

func (*NewLineStream) Data ΒΆ added in v0.4.0

func (s *NewLineStream) Data() []byte

func (*NewLineStream) Err ΒΆ added in v0.4.0

func (s *NewLineStream) Err() error

func (*NewLineStream) Next ΒΆ added in v0.4.0

func (s *NewLineStream) Next(_ context.Context) bool

type ProxyStream ΒΆ added in v0.4.0

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

func (*ProxyStream) Data ΒΆ added in v0.4.0

func (s *ProxyStream) Data() []byte

func (*ProxyStream) Err ΒΆ added in v0.4.0

func (s *ProxyStream) Err() error

func (*ProxyStream) Next ΒΆ added in v0.4.0

func (s *ProxyStream) Next(_ context.Context) bool

type ReqOption ΒΆ

type ReqOption interface {
	Configure(r Request) error
}

func BaseURL ΒΆ added in v0.8.0

func BaseURL(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 {
	Method() string
	SetMethod(string)

	SetURL(*url.URL)
	// SetBodyStream sets the stream of body data belonging to a request. bodySize parameter is needed
	// when using fasthttp implementation.
	SetBodyStream(rc io.ReadWriteCloser, bodySize int)
	SetBody([]byte)

	Body() []byte
	BodyStream() io.ReadWriteCloser

	URL() *url.URL
	// contains filtered or unexported methods
}

type ResOption ΒΆ

type ResOption interface {
	Parse(r Response) error
}

func MockedRes ΒΆ added in v0.8.0

func MockedRes(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)
	// contains filtered or unexported methods
}

type Slice ΒΆ added in v0.3.0

type Slice[T any] []T

func (Slice[T]) Range ΒΆ added in v0.3.0

func (s Slice[T]) Range(fn func(int, T) bool)

func (Slice[T]) Serialize ΒΆ added in v0.4.0

func (s Slice[T]) Serialize() bool

type Stream ΒΆ

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

func NewCSVStream ΒΆ added in v0.6.0

func NewCSVStream[T any](r io.Reader, ignoreLines int, parser csvparser.Parser[T]) Stream[T]

func NewJSONEachRowStream ΒΆ

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

func NewNewLineStream ΒΆ added in v0.4.0

func NewNewLineStream(r io.Reader) Stream[[]byte]

func NewProxyStream ΒΆ added in v0.4.0

func NewProxyStream(r io.Reader, bufferSize int) Stream[[]byte]

type StreamCallReqOption ΒΆ added in v0.3.0

type StreamCallReqOption[T any] interface {
	CallReqOption[T]
	// contains filtered or unexported methods
}

type StreamCallReqOptionFunc ΒΆ added in v0.3.0

type StreamCallReqOptionFunc[T any] func(c *Call[T], req Request) error

func RequestStreamBody ΒΆ added in v0.8.0

func RequestStreamBody[T, U any](r rangeable[U]) StreamCallReqOptionFunc[T]

func (StreamCallReqOptionFunc[T]) Configure ΒΆ added in v0.3.0

func (s StreamCallReqOptionFunc[T]) Configure(c *Call[T], req Request) error

type StreamFactory ΒΆ

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

func NewCSVStreamFactory ΒΆ added in v0.6.0

func NewCSVStreamFactory[T any](ignoreLines int, parser csvparser.Parser[T]) StreamFactory[T]

func NewJSONEachRowStreamFactory ΒΆ

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

func NewNewLineStreamFactory ΒΆ added in v0.4.0

func NewNewLineStreamFactory() StreamFactory[[]byte]

func NewProxyStreamFactory ΒΆ added in v0.4.0

func NewProxyStreamFactory(bufferSize int) StreamFactory[[]byte]

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]

type StreamFromReader ΒΆ added in v0.4.0

type StreamFromReader struct {
	io.Reader
	// contains filtered or unexported fields
}

func NewStreamFromReader ΒΆ added in v0.4.0

func NewStreamFromReader(r io.Reader, sf StreamFactory[[]byte]) StreamFromReader

func (StreamFromReader) Range ΒΆ added in v0.4.0

func (r StreamFromReader) Range(fn func(int, []byte) bool)

func (StreamFromReader) Serialize ΒΆ added in v0.4.0

func (r StreamFromReader) Serialize() bool

Directories ΒΆ

Path Synopsis

Jump to

Keyboard shortcuts

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