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.


DocumentationTest ExamplesIssuesDiscussions

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