Help us shape the future of Go! Take the 2026 Go Developer Survey

shoot

package module
v1.0.0 Latest Latest
Warning

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

Go to latest
Published: Oct 27, 2026 License: MIT Imports: 18 Imported by: 0

README

GAP Logo

shoot

Language CI

A pack of tools for "go generate".

How to use?

Usage: shoot <subcommand> [options]
These are all the sub commands supported as of now:
new [-opt] [-getset] [-json] [-exp] [-tagcase=<case>] [-sign=<prefix>] [-type=<Type> | -file=<GoFile>] [dir] [-sep] [-v]
enum [-bit] [-json] [-text] [-sql] [-gorm] [-type=<Type> | -file=<GoFile>] [dir] [-sep] [-v]
rest [-sign=<prefix>] [-type=<Type> | -file=<GoFile>] [dir] [-sep] [-v]
map [-path=<path>] [-alias=<alias>] [-to=<DestType>] [-way=<way>] [-i] [-type=<SrcType> | -file=<GoFile>] [dir] [-sep] [-v]

new and rest instructions use @ by default, for example //@new and //@Get("/users/{id}"). Use -sign=<prefix> to select another instruction prefix; -sign='shoot:' keeps compatibility with the former //shoot: form.

using go1.24+ (SUGGESTED)

why 1.24

Tool dependencies

install
go get -tool github.com/loopopen/shoot/cmd/shoot@latest
generate instruction examples
//go:generate go tool shoot new -getset -json -type=YourType

//go:generate go tool shoot new -getset -json -file=$GOFILE

//go:generate go tool shoot enum -json -type=YourEnum

//go:generate go tool shoot rest -type=YourClient

//go:generate go tool shoot map -path=../destpath -type=YourSrcType
go generate			# run in the current directory
go generate ./...	# recursively run in the current directory and its subdirectories

Constructor example:

// Code generated by "shoot new -getset -type=User"; DO NOT EDIT.

package example

// NewUser constructs a new instance of type User
func NewUser(id int, name string, age int) *User {
	return &User{
		id:   id,
		name: name,
		age:  age,
	}
}

// Id gets the value of field id
func (u *User) Id() int {
	return u.id
}

// Name gets the value of field name
func (u *User) Name() string {
	return u.name
}

// Age gets the value of field age
func (u *User) Age() int {
	return u.age
}

// SetId sets the value of field id
func (u *User) SetId(id_ int) {
	u.id = id_
}

// SetName sets the value of field name
func (u *User) SetName(name_ string) {
	u.name = name_
}

// SetAge sets the value of field age
func (u *User) SetAge(age_ int) {
	u.age = age_
}

REST client example:

package example

import (
	"context"
	"fmt"
	"time"

	"github.com/loopopen/shoot"
)

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

type Client interface {
	//@headers={Tenant-Id:123}
	shoot.RestClient[Client]

	//@Get("/users/{id}")
	//@alias={userID:id},{pageSize:size}
	GetUser(ctx context.Context, userID string, pageSize int, opts ...shoot.RequestOption) (*User, *shoot.Response, error)

	//@Post("/users")
	CreateUser(ctx context.Context, user User, opts ...shoot.RequestOption) (*User, *shoot.Response, error)

	//@Get("/download")
	Download(ctx context.Context) (*shoot.StreamResponse, error)
}

func Example() error {
	client := shoot.NewRest[Client](
		shoot.BaseURL("https://api.example.com"),
		shoot.Timeout("3s"),
		shoot.DefaultHeaders(map[string]string{"X-App": "example"}),
	)

	user, response, err := client.GetUser(
		context.Background(),
		"a/b", // path parameters are URL-escaped by generated clients
		20,
		shoot.WithBearerToken("token"),
		shoot.WithHeader("X-Request-ID", "request-123"),
		shoot.WithQueryParam("locale", "en"),
		shoot.WithTimeout(2*time.Second),
	)
	if err != nil {
		return err
	}
	if response.IsFailure() {
		return fmt.Errorf("request failed: %s", response.String())
	}
	_ = user
	return nil
}

Run shoot rest after declaring the interface. A generated method can accept ...shoot.RequestOption to customize one request. The variadic parameter must be named; placing it last is recommended. Available options are:

  • WithHeader, WithHeaders, WithBearerToken, WithBasicAuth, WithAccept, WithContentType, and WithUserAgent
  • WithQueryParam and WithQueryParams
  • WithCookie and WithCookies
  • WithTimeout and WithDeadline
  • WithRetryCount, WithRetryWait, WithRetryStrategy, WithRetryCondition, WithAllowNonIdempotentRetry, and WithoutDefaultRetryConditions
  • WithRequestModifier for custom request mutations

Request options take precedence over generated defaults, client-level default headers, and @headers instructions. shoot.Timeout and WithTimeout bound each attempt. The caller's context and WithDeadline bound the whole call, including retries and the waits between them. A non-positive WithTimeout disables the client-level per-attempt timeout.

shoot.WithRetry sets the client-level policy. RetryConfig.Count is the number of additional attempts. Retries run outside http.Client.Do. By default only idempotent methods are retried, on temporary network errors, per-attempt timeouts, HTTP 429, and HTTP 500 and above except 501. POST and PATCH retry only when the policy or the request allows it. A Retry-After header on 429 and 503 overrides the backoff. The default backoff is capped exponential delay with jitter.

Generated clients URL-escape path parameters. GET and DELETE parameters that are not used in the path become query parameters; a query map must have string keys. POST, PUT, and PATCH accept at most one non-path body parameter, and may also have no body.

*shoot.Response caches and closes the response body. HTTP failure responses are still returned and, when a result type is declared, decoded; inspect IsSuccess, IsFailure, StatusCode, Body, or String. A *shoot.StreamResponse leaves the body open, so the caller must close it.

Mapper example:

// Code generated by "shoot map -path=../../domain/model -alias=domain -type=*"; DO NOT EDIT.

package dto

import domain "mapperexample/domain/model"

// ToDomain converts receiver to type domain.Order
func (o *Order) ToDomain() *domain.Order {
	if o == nil {
		return nil
	}
	order_ := new(domain.Order)
	order_.ID = o.ID
	order_.Amount = o.StringToDecimal(o.Amount)
	order_.Status = o.Status
	order_.OrderTime = o.StringToTime(o.OrderingTime)
	if o.Address != nil {
		order_.Address = *o.Address.ToDomain()
	}
	o.writeDomain(order_)
	return order_
}

// FromDomain reads from type domain.Order, then writes back to receiver and returns it
func (o *Order) FromDomain(order_ *domain.Order) *Order {
	if order_ == nil {
		return nil
	}
	if o == nil {
		o = new(Order)
	}
	o.ID = order_.ID
	o.Amount = o.DecimalToString(order_.Amount)
	o.Status = order_.Status
	o.OrderingTime = o.TimeToString(order_.OrderTime)
	o.Address = new(OrderAddress).FromDomain(&order_.Address)
	o.readDomain(order_)
	return o
}

more examples:

Inspiring projects

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func Do added in v0.9.0

func Do(client *http.Client, req *http.Request, base RetryConfig, call Call) (*http.Response, error)

Do sends req with client, retrying outside http.Client.Do.

call comes from ApplyRequestOptions. Its timeout is applied separately to each attempt. The request context, including a WithDeadline budget, bounds every attempt and the waits between them. The returned response body stays open; closing it cancels the winning attempt. The caller still cancels the overall deadline with Call.Cancel.

func IsEnum

func IsEnum[T constraints.EnumShooter[T], TV constraints.Integer](value TV) bool

IsEnum checks whether a given integer value is a valid enum value of type T. Useful for validating raw input before casting or using it as an enum.

func NewRest

func NewRest[T RestClient[T]](opts ...Option[RestConf, *RestConf]) T

NewRest creates a new instance of type T that implements the RestClient interface.

func NewWith

func NewWith[T any, PT constraints.NewShooter[T]](opts ...Option[T, PT]) *T

NewWith creates a new instance of type T using the functional options pattern. It first initializes the instance with default values via SetDefault, then applies each provided Option in order. This pattern promotes clean, declarative construction of configurable types.

func ParseEnum

func ParseEnum[T constraints.EnumShooter[T]](str string) (T, error)

ParseEnum attempts to convert a string into its corresponding enum value. It uses the ValueMap() provided by the enum type to look up the value. Returns an error if the string does not match any known enum value.

func Register

func Register[T RestClient[T]](ctor func(RestConf) T)

Register associates a constructor function with a specific RestClient implementation. The constructor must accept a RestConf and return a concrete type that satisfies RestClient.

func SetQuery added in v0.9.2

func SetQuery(q url.Values, key string, value any, opt QueryOpt) error

SetQuery writes value into q under key. Nil pointers are skipped. OmitEmpty also skips zero values. time.Time uses DateFormat, Unix, or UnixMilli when set; UTC converts the time before that formatting. Slices and arrays repeat the key, unless CSV joins them with commas.

func TryParseEnum

func TryParseEnum[T constraints.EnumShooter[T]](str string, v *T) bool

TryParseEnum is a safe variant of ParseEnum. It attempts to parse the string into an enum value and stores the result in v. Returns true if successful, false otherwise. Does not return an error.

Types

type Call added in v0.9.0

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

Call is the resolved per-request policy produced by ApplyRequestOptions. Cancel releases the overall deadline. Per-attempt timeouts are applied by Do.

func ApplyRequestOptions added in v0.8.3

func ApplyRequestOptions(req *http.Request, defaultTimeout time.Duration, options ...RequestOption) (Call, error)

ApplyRequestOptions applies request options and returns the call policy. It is primarily intended for code generated by shoot. Cancel must be called after the response body has been consumed. A positive timeout is recorded for each attempt and is not attached to the request context here; a deadline is attached immediately and bounds the whole call, including retries.

func (Call) Cancel added in v0.9.0

func (c Call) Cancel()

Cancel releases the overall deadline set by WithDeadline.

type Option

type Option[T any, PT constraints.NewShooter[T]] func(*T)

Option defines a functional option for configuring an instance of type T. PT is a pointer type that satisfies DefaultSetter[T], allowing default setup.

func BaseURL

func BaseURL(baseURL_ string) Option[RestConf, *RestConf]

BaseURL is a configuration for the filed baseURL

func DefaultHeaders

func DefaultHeaders(defaultHeaders_ map[string]string) Option[RestConf, *RestConf]

DefaultHeaders is a configuration for the filed defaultHeaders

func EnableLogging

func EnableLogging(enableLogging_ bool) Option[RestConf, *RestConf]

EnableLogging is a configuration for the filed enableLogging

func MaxResponseSize added in v0.9.2

func MaxResponseSize(maxResponseSize_ string) Option[RestConf, *RestConf]

MaxResponseSize is a configuration for the filed maxResponseSize

func Retry added in v0.9.0

func Retry(retry_ RetryConfig) Option[RestConf, *RestConf]

Retry is a configuration for the filed retry

func Timeout

func Timeout(timeout_ string) Option[RestConf, *RestConf]

Timeout is a configuration for the filed timeout

func Use

func Use(middleware middleware.Middleware) Option[RestConf, *RestConf]

Use returns an Option function that applies the given middleware to a RestConf instance.

func WithRetry added in v0.9.0

func WithRetry(cfg RetryConfig) Option[RestConf, *RestConf]

WithRetry sets the client-level retry policy. Request options can override the count, wait, strategy, idempotency, and conditions for one call.

type QueryOpt added in v0.9.2

type QueryOpt struct {
	DateFormat string
	Unix       bool
	UnixMilli  bool
	UTC        bool
	CSV        bool
	OmitEmpty  bool
}

QueryOpt controls how one value is encoded into a query string. Zero options use the default encoding: scalars are printed, and slices repeat the key once per element.

type RequestOption added in v0.8.3

type RequestOption interface {
	// contains filtered or unexported methods
}

RequestOption customizes a single outgoing HTTP request.

A generated REST method may optionally accept ...RequestOption as its last parameter. Options are applied after configured and statically declared headers, so request-specific values take precedence.

func WithAccept added in v0.8.3

func WithAccept(mediaType string) RequestOption

WithAccept sets the Accept header.

func WithAllowNonIdempotentRetry added in v0.9.0

func WithAllowNonIdempotentRetry() RequestOption

WithAllowNonIdempotentRetry allows POST and PATCH to be retried for one request.

func WithBasicAuth added in v0.8.3

func WithBasicAuth(username, password string) RequestOption

WithBasicAuth sets the Authorization header using HTTP Basic authentication.

func WithBearerToken added in v0.8.3

func WithBearerToken(token string) RequestOption

WithBearerToken sets the Authorization header using Bearer authentication.

func WithContentType added in v0.8.3

func WithContentType(mediaType string) RequestOption

WithContentType sets the Content-Type header.

func WithCookie added in v0.8.3

func WithCookie(cookie *http.Cookie) RequestOption

WithCookie adds a cookie to a single outgoing HTTP request.

func WithCookies added in v0.8.3

func WithCookies(cookies ...*http.Cookie) RequestOption

WithCookies adds cookies to a single outgoing HTTP request.

func WithDeadline added in v0.8.3

func WithDeadline(deadline time.Time) RequestOption

WithDeadline sets an absolute deadline for the whole call, including retries and the waits between them. A per-attempt timeout still applies inside the time that remains.

func WithHeader added in v0.8.3

func WithHeader(name, value string) RequestOption

WithHeader sets a header on a single outgoing HTTP request.

func WithHeaders added in v0.8.3

func WithHeaders(headers http.Header) RequestOption

WithHeaders sets headers on a single outgoing HTTP request. Header values replace existing values with the same name.

func WithMaxResponseBytes added in v0.9.2

func WithMaxResponseBytes(n int64) RequestOption

WithMaxResponseBytes sets the response body limit for one call. Zero or negative removes the limit, including a client-level default. The value is stored on the request context and read by the client transport.

func WithMaxResponseSize added in v0.9.2

func WithMaxResponseSize(size string) RequestOption

WithMaxResponseSize sets the response body limit for one call using a size string such as "20m" or "1g". "0" or an empty string removes the limit.

func WithQueryParam added in v0.8.3

func WithQueryParam(key, value string) RequestOption

WithQueryParam sets one query parameter, replacing existing values for key.

func WithQueryParams added in v0.8.3

func WithQueryParams(values url.Values) RequestOption

WithQueryParams sets query parameters, replacing existing values for each supplied key while preserving multiple supplied values.

func WithRequestModifier added in v0.8.3

func WithRequestModifier(modifier func(*http.Request) error) RequestOption

WithRequestModifier applies a custom request mutation. Use it for request properties that do not have a dedicated option.

func WithRetryCondition added in v0.9.0

func WithRetryCondition(condition RetryCondition) RequestOption

WithRetryCondition adds a retry condition for one request. Request conditions run after the defaults and before client-level conditions. The first condition that returns true selects a retry.

func WithRetryCount added in v0.9.0

func WithRetryCount(count int) RequestOption

WithRetryCount overrides the number of additional attempts for one request.

func WithRetryStrategy added in v0.9.0

func WithRetryStrategy(strategy RetryDelayStrategy) RequestOption

WithRetryStrategy overrides the delay strategy for one request. A Retry-After header on 429 and 503 is still honored first.

func WithRetryWait added in v0.9.0

func WithRetryWait(wait, max time.Duration) RequestOption

WithRetryWait overrides the backoff window for one request. wait is the base delay and max is the cap used by the default strategy.

func WithTimeout added in v0.8.3

func WithTimeout(timeout time.Duration) RequestOption

WithTimeout sets the per-attempt timeout for a single request. Each retry receives a fresh timeout derived from the parent context, so it cannot extend the caller's context or a WithDeadline budget. A non-positive duration disables the client-level per-attempt timeout for that request.

func WithUserAgent added in v0.8.3

func WithUserAgent(userAgent string) RequestOption

WithUserAgent sets the User-Agent header.

func WithoutDefaultRetryConditions added in v0.9.0

func WithoutDefaultRetryConditions() RequestOption

WithoutDefaultRetryConditions disables the built-in status and network conditions for one request. Conditions added explicitly still run.

type Response added in v0.8.1

type Response struct {
	RawResponse *http.Response
	// contains filtered or unexported fields
}

Response wraps the response returned by net/http.

Body contains a cached copy of the response payload. RawResponse.Body has already been consumed and closed by the generated client.

func NewResponse added in v0.8.1

func NewResponse(rawResponse *http.Response, body []byte) *Response

NewResponse constructs a Response for generated clients.

func (*Response) Body added in v0.8.1

func (r *Response) Body() []byte

Body returns the response payload cached by the generated client.

func (*Response) Close added in v0.8.1

func (r *Response) Close() error

Close closes the underlying response body. Generated clients have normally closed it already.

func (*Response) Cookies added in v0.8.1

func (r *Response) Cookies() []*http.Cookie

Cookies returns the cookies included in the response.

func (*Response) Header added in v0.8.1

func (r *Response) Header() http.Header

Header returns the response headers.

func (*Response) IsFailure added in v0.8.4

func (r *Response) IsFailure() bool

IsFailure reports whether the status code is 4xx or 5xx.

func (*Response) IsSuccess added in v0.8.1

func (r *Response) IsSuccess() bool

IsSuccess reports whether the status code is in the 2xx range.

func (*Response) Proto added in v0.8.1

func (r *Response) Proto() string

Proto returns the HTTP protocol used for the response.

func (*Response) RawBody added in v0.8.1

func (r *Response) RawBody() io.ReadCloser

RawBody returns the consumed and closed underlying response body. Use StreamResponse for responses that must be read incrementally.

func (*Response) Size added in v0.8.1

func (r *Response) Size() int64

Size returns the size of the cached response payload.

func (*Response) Status added in v0.8.1

func (r *Response) Status() string

Status returns the HTTP status text, for example "200 OK".

func (*Response) StatusCode added in v0.8.1

func (r *Response) StatusCode() int

StatusCode returns the HTTP status code.

func (*Response) String added in v0.8.1

func (r *Response) String() string

String returns the cached response payload as a trimmed string.

type RestClient

type RestClient[T any] interface {
	ConfigHTTPClient(config func(client *http.Client)) T
	ShootRest()
}

RestClient defines the interface for REST-capable clients.

type RestConf

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

RestConf holds configuration parameters for initializing a RestClient.

func NewRestConf

func NewRestConf(baseUrl string, timeout string, enableLogging bool, maxResponseSize string, defaultHeaders map[string]string, retry RetryConfig) *RestConf

NewRestConf constructs a new instance of type RestConf

func (*RestConf) BaseURL

func (r *RestConf) BaseURL() string

BaseURL gets the value of field baseURL

func (*RestConf) BuildMiddleware

func (r *RestConf) BuildMiddleware() http.RoundTripper

BuildMiddleware constructs the middleware chain by wrapping a transport cloned from http.DefaultTransport. Each client gets that transport's settings and its own connection pool. The response-size limit is outermost so it applies to the body the caller reads.

func (*RestConf) DefaultHeaders

func (r *RestConf) DefaultHeaders() map[string]string

DefaultHeaders gets the value of field defaultHeaders

func (*RestConf) EnableLogging

func (r *RestConf) EnableLogging() bool

EnableLogging gets the value of field enableLogging

func (*RestConf) MaxResponseSize added in v0.9.2

func (r *RestConf) MaxResponseSize() string

MaxResponseSize gets the value of field maxResponseSize

func (*RestConf) Retry added in v0.9.0

func (r *RestConf) Retry() RetryConfig

Retry gets the value of field retry

func (*RestConf) SetBaseURL

func (r *RestConf) SetBaseURL(baseURL_ string)

SetBaseURL sets the value of field baseURL

func (*RestConf) SetDefault added in v0.9.0

func (r *RestConf) SetDefault()

SetDefault sets the default values

func (*RestConf) SetDefaultHeaders

func (r *RestConf) SetDefaultHeaders(defaultHeaders_ map[string]string)

SetDefaultHeaders sets the value of field defaultHeaders

func (*RestConf) SetEnableLogging

func (r *RestConf) SetEnableLogging(enableLogging_ bool)

SetEnableLogging sets the value of field enableLogging

func (*RestConf) SetMaxResponseSize added in v0.9.2

func (r *RestConf) SetMaxResponseSize(maxResponseSize_ string)

SetMaxResponseSize sets the value of field maxResponseSize

func (*RestConf) SetRetry added in v0.9.0

func (r *RestConf) SetRetry(retry_ RetryConfig)

SetRetry sets the value of field retry

func (*RestConf) SetTimeout

func (r *RestConf) SetTimeout(timeout_ string)

SetTimeout sets the value of field timeout

func (RestConf) ShootNew

func (r RestConf) ShootNew()

ShootNew exists solely to fulfill the NewShooter interface contract

func (*RestConf) Timeout

func (r *RestConf) Timeout() string

Timeout gets the value of field timeout

func (*RestConf) With

func (r *RestConf) With(opts ...Option[RestConf, *RestConf]) *RestConf

With initializes this instance using the functional options pattern

type RestConfGetter

type RestConfGetter interface {
	BaseURL() string
	Timeout() string
	EnableLogging() bool
	MaxResponseSize() string
	DefaultHeaders() map[string]string
	Retry() RetryConfig
}

RestConfGetter is read-only interface for RestConf type

type RestConfSetter

type RestConfSetter interface {
	SetBaseURL(string)
	SetTimeout(string)
	SetEnableLogging(bool)
	SetMaxResponseSize(string)
	SetDefaultHeaders(map[string]string)
	SetRetry(RetryConfig)
}

RestConfSetter is write-only interface for RestConf type

type RetryCondition added in v0.9.0

type RetryCondition func(resp *http.Response, err error) bool

RetryCondition reports whether a finished attempt should be retried. resp is nil when the transport fails before a response arrives.

type RetryConfig added in v0.9.0

type RetryConfig struct {
	Count              int
	Wait               time.Duration
	MaxWait            time.Duration
	AllowNonIdempotent bool
	DisableDefaults    bool
	Conditions         []RetryCondition
	Strategy           RetryDelayStrategy
}

RetryConfig is the client-level retry policy. Count is the number of additional attempts, so the total number of attempts is Count + 1. A zero Count disables retries. POST and PATCH are not retried unless AllowNonIdempotent is set.

type RetryDelayStrategy added in v0.9.0

type RetryDelayStrategy func(resp *http.Response, err error, attempt int) (time.Duration, error)

RetryDelayStrategy chooses how long to wait after a failed attempt. attempt is the 1-based index of the attempt that just failed.

func RetryConstantDelay added in v0.9.0

func RetryConstantDelay(delay time.Duration) RetryDelayStrategy

RetryConstantDelay waits the same duration before every retry.

type StreamResponse added in v0.8.1

type StreamResponse struct {
	RawResponse *http.Response
}

StreamResponse wraps an HTTP response whose body has not been consumed. The caller must close it after reading, including when the request returns a non-nil error together with a StreamResponse.

func NewStreamResponse added in v0.8.1

func NewStreamResponse(rawResponse *http.Response, cleanups ...func()) *StreamResponse

NewStreamResponse constructs a StreamResponse for generated clients. An optional cleanup function runs once when the response body is closed.

func (*StreamResponse) Body added in v0.8.1

func (r *StreamResponse) Body() io.ReadCloser

Body returns the underlying response stream. The caller must close it.

func (*StreamResponse) Close added in v0.8.1

func (r *StreamResponse) Close() error

Close closes the underlying response stream.

func (*StreamResponse) Cookies added in v0.8.1

func (r *StreamResponse) Cookies() []*http.Cookie

Cookies returns the cookies included in the response.

func (*StreamResponse) Header added in v0.8.1

func (r *StreamResponse) Header() http.Header

Header returns the response headers.

func (*StreamResponse) IsFailure added in v0.8.4

func (r *StreamResponse) IsFailure() bool

IsFailure reports whether the status code is 4xx or 5xx.

func (*StreamResponse) IsSuccess added in v0.8.1

func (r *StreamResponse) IsSuccess() bool

IsSuccess reports whether the status code is in the 2xx range.

func (*StreamResponse) Proto added in v0.8.1

func (r *StreamResponse) Proto() string

Proto returns the HTTP protocol used for the response.

func (*StreamResponse) Status added in v0.8.1

func (r *StreamResponse) Status() string

Status returns the HTTP status text, for example "200 OK".

func (*StreamResponse) StatusCode added in v0.8.1

func (r *StreamResponse) StatusCode() int

StatusCode returns the HTTP status code.

Jump to

Keyboard shortcuts

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