httpclient

package
v1.0.2 Latest Latest
Warning

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

Go to latest
Published: Oct 9, 2026 License: MIT Imports: 22 Imported by: 0

Documentation

Overview

Package httpclient builds and sends the requests of a generated client and reads its responses.

Index

Constants

This section is empty.

Variables

View Source
var (
	ErrBaseURL   = errors.New("invalid base URL")
	ErrFrame     = errors.New("invalid stream frame")
	ErrFrameSize = errors.New("stream frame too large")
)

Functions

func DecodeResponse

func DecodeResponse(res *http.Response, body []byte, targets []ResponseTarget, unmarshal func(data []byte, v any) error) error

DecodeResponse fills the targets of a response: those of its status, else of its range, else of default, taking the body target whose media type fits the response's best. A status nothing documents, a media type no target takes and an empty body leave everything as it is. JSON is read with unmarshal.

func DecodeSuccess

func DecodeSuccess(res *http.Response, body []byte, targets []ResponseTarget, unmarshal func(data []byte, v any) error) error

DecodeSuccess is DecodeResponse for a method that returns the body of a 2xx response. A 2xx takes the targets of its code or its range only, never default, and one that none lists is an *APIError when any target lists a 2xx; without such a target, which is a method that returns no body, it is no error. A body in a media type no target of the status takes is an error. A status outside 2xx is an *APIError, which carries the body decoded into the target of the status when that is an error type.

func IsStreaming

func IsStreaming(res *http.Response) bool

IsStreaming reports a 2xx response with a body in a sequential media type, which SendStream leaves unread for a Stream.

func ParseBaseURL

func ParseBaseURL(s string) (*url.URL, error)

ParseBaseURL parses the base URL of a client, which needs a scheme and a host.

func Send

func Send(d Doer, req *http.Request, accept string, timeout time.Duration) (*http.Response, []byte, error)

Send sends req with d and reads the whole body, which it closes. A timeout above 0 bounds the whole call, the body read included. The response comes back with the body in memory, so it can be read again. It asks for accept unless the request says what it accepts.

func SendStream

func SendStream(d Doer, req *http.Request, mediaType string, timeout time.Duration) (*http.Response, []byte, error)

SendStream is Send for a method that streams: it asks for mediaType unless the request says what it accepts, and leaves the body of a response IsStreaming reports unread, with no bytes returned. Every other response is read whole, as Send reads it. A timeout above 0 bounds the call until a stream starts: the wait for its headers, or the whole call for any other response. Closing the body of a stream ends its request.

Types

type APIError

type APIError struct {
	StatusCode int
	Header     http.Header
	Body       []byte
	Err        error
}

APIError is a response that a method returning the body of a 2xx response does not take: a status outside 2xx, or a 2xx the spec does not list. Err is the body decoded into the error type the spec documents for the status, nil without one; it is what errors.As unwraps to.

func (*APIError) Error

func (e *APIError) Error() string

func (*APIError) Unwrap

func (e *APIError) Unwrap() error

type Doer

type Doer interface {
	Do(req *http.Request) (*http.Response, error)
}

Doer sends a request, as *http.Client does.

type Event

type Event struct {
	ID    string
	Type  string
	Retry time.Duration
	Data  []byte
}

Event is one frame of a stream: the fields of a Server-Sent Event, or, on a line-delimited stream, the line in Data alone. ID is the last event ID, which stays from one event to the next until an id field changes it; Type is the event field; Retry is the reconnection time the server asks for, 0 when the event names none.

type RequestBuilder

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

RequestBuilder puts a request together: the path with its parameters, the query, the headers, the cookies and the body. The first error stops the rest and comes back from Build.

func NewRequestBuilder

func NewRequestBuilder(method, path string) *RequestBuilder

NewRequestBuilder starts a request of method to path, a template such as /pets/{id} whose placeholders PathParam fills in. A query the template writes after a ? is sent as written, ahead of the query parameters; a fragment after a # is not sent.

func (*RequestBuilder) Build

func (b *RequestBuilder) Build(ctx context.Context, base *url.URL) (*http.Request, error)

Build makes the request against base: the path goes after the base's, the query is the base's, then the template's, the query parameters in the order they were added and the querystring, and a File body streams. The fragment of base is not sent. A placeholder no PathParam filled is missing.

func (*RequestBuilder) BytesBody

func (b *RequestBuilder) BytesBody(data []byte, mediaType string)

BytesBody sends data as it is under mediaType.

func (*RequestBuilder) CookieParam

func (b *RequestBuilder) CookieParam(v any, p runtime.Param)

CookieParam adds v as the cookie p, left out as QueryParam leaves it. A value with a byte no cookie holds, such as a semicolon, is an error rather than sent altered.

func (*RequestBuilder) FileBody

func (b *RequestBuilder) FileBody(f runtime.File, mediaType string)

FileBody streams f under mediaType, or under the file's own content type when mediaType is empty, with its size as the content length when it is known.

func (*RequestBuilder) FormBody

func (b *RequestBuilder) FormBody(v any, enc runtime.Encoding)

FormBody sends v as application/x-www-form-urlencoded with the encoding enc, see runtime.EncodeForm.

func (*RequestBuilder) HeaderParam

func (b *RequestBuilder) HeaderParam(v any, p runtime.Param)

HeaderParam adds v as the header p, left out as QueryParam leaves it.

func (*RequestBuilder) JSONBody

func (b *RequestBuilder) JSONBody(v any, mediaType string, marshal func(v any) ([]byte, error))

JSONBody sends v as JSON under mediaType, written by marshal.

func (*RequestBuilder) MultipartBody

func (b *RequestBuilder) MultipartBody(v any, enc runtime.Encoding)

MultipartBody sends v as multipart/form-data, see runtime.WriteMultipart. The form is written while it is sent, so its files stream; its length is known up front when every file knows its size.

func (*RequestBuilder) PathParam

func (b *RequestBuilder) PathParam(v any, p runtime.Param)

PathParam fills v into the placeholder of p. A nil value is an error, since paths need every parameter, and so is a value written as nothing, which would send the request to another path.

func (*RequestBuilder) QueryParam

func (b *RequestBuilder) QueryParam(v any, p runtime.Param)

QueryParam adds v to the query as p, see runtime.EncodeQuery. An optional p is left out when v is nil or zero, a required one is an error when v is nil.

func (*RequestBuilder) QueryString

func (b *RequestBuilder) QueryString(v any, p runtime.Param)

QueryString writes v as the whole query, JSON or a form; v is left out as QueryParam leaves it.

func (*RequestBuilder) TextBody

func (b *RequestBuilder) TextBody(s, mediaType string)

TextBody sends s as it is under mediaType.

func (*RequestBuilder) TextValueBody

func (b *RequestBuilder) TextValueBody(v any, mediaType string)

TextValueBody sends v, a number, a boolean or a value that marshals to text, as its text under mediaType.

type ResponseTarget

type ResponseTarget struct {
	Status    string
	MediaType string
	Dst       any
	IsHeaders bool
}

ResponseTarget is a field one documented response is decoded into. Status is the status as the spec writes it: 200, 2XX or default; MediaType is the content's and Dst points at the field. With IsHeaders, Dst is the struct of the typed headers of the status, read from the response headers. Without Dst, the target documents a status whose body is not read.

type Stream

type Stream[T any] struct {
	Sentinels    []string
	MaxFrameSize int
	Unmarshal    func(data []byte, v any) error
	// contains filtered or unexported fields
}

Stream reads the frames of a response one at a time, as bufio.Scanner does: Next reads the next frame into Current, and Err reports what stopped Next. The caller owns the response and closes the stream. Sentinels are frames that end the stream instead of being decoded, such as the [DONE] some APIs send last; MaxFrameSize is the most bytes one line of the body, or the data of one event, may hold, 0 for no limit; Unmarshal reads a frame that is not []byte, json.Unmarshal when it is nil. Set them before the first Next. Canceling the context of the request unblocks a pending Next, and Err then reports the context's error. Close, called from another goroutine, unblocks it too, and Err then reports nil.

func DecodeStream

func DecodeStream[T any](res *http.Response, body []byte, targets []ResponseTarget, unmarshal func(data []byte, v any) error) (*Stream[T], error)

DecodeStream is DecodeResponse for a response SendStream returned with its body. A streamed response fills the typed headers of its status and comes back as a stream, closed when a header does not decode. Any other response is decoded whole and gives no stream. JSON is read with unmarshal.

func NewEventStream

func NewEventStream[T any](res *http.Response) *Stream[T]

NewEventStream reads the body of res as Server-Sent Events. An event's data lines are joined with newlines; comments are skipped; an event without data is skipped too, after its id and retry are taken. A line ends in LF, CRLF or a lone CR, and a byte order mark at the start of the body is dropped. An event with data that the body ends before its blank line is not delivered, and Err reports io.ErrUnexpectedEOF.

func NewLineStream

func NewLineStream[T any](res *http.Response) *Stream[T]

NewLineStream reads the body of res one line at a time, skipping lines that are empty or hold only spaces.

func NewStream

func NewStream[T any](res *http.Response) *Stream[T]

NewStream frames the body of res by its Content-Type: Server-Sent Events for text/event-stream, else one frame per line.

func OpenStream

func OpenStream[T any](res *http.Response, body []byte, targets []ResponseTarget, unmarshal func(data []byte, v any) error) (*Stream[T], error)

OpenStream returns a stream over the frames of a response SendStream returned with its body. A 2xx response without a body, such as 204, is a stream without frames; one in another media type is ErrContentType. A status outside 2xx is an *APIError, as DecodeSuccess reports it with targets. The stream and the error read JSON with unmarshal.

func (*Stream[T]) All

func (s *Stream[T]) All() iter.Seq2[T, error]

All iterates over the frames, delivering the error that stops the stream as the last pair.

func (*Stream[T]) Close

func (s *Stream[T]) Close() error

Close closes the response body. Next returns false afterwards.

func (*Stream[T]) Current

func (s *Stream[T]) Current() T

Current is the frame the last Next read.

func (*Stream[T]) Err

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

Err is what stopped Next: nil at the end of the stream, at a sentinel or after Close, else the read or decode error, io.ErrUnexpectedEOF when an event stream ends inside an event, or the error of the request's context when it was canceled.

func (*Stream[T]) Event

func (s *Stream[T]) Event() Event

Event is the raw frame behind Current, with the id, event and retry fields of a Server-Sent Event.

func (*Stream[T]) Next

func (s *Stream[T]) Next() bool

Next reads the next frame into Current and reports whether there was one. It returns false at the end of the stream, at a sentinel, after Close, and on an error, which Err then reports. A stream of anything but []byte skips an event whose data is empty, which no type decodes from.

Jump to

Keyboard shortcuts

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