Documentation
¶
Index ¶
- Constants
- Variables
- func AutoRegister(api API, server any)
- func DefaultSchemaNamer(t reflect.Type, hint string) string
- func FieldSelectTransform(ctx Context, status string, v any) (any, error)
- func Register[I, O any](api API, op Operation, handler func(context.Context, *I) (*O, error))
- func SetReadDeadline(w http.ResponseWriter, deadline time.Time) error
- func Validate(r Registry, s *Schema, path *PathBuffer, mode ValidateMode, v any, ...)
- func WithOptions[Options any](f func(cmd *cobra.Command, args []string, options *Options)) func(*cobra.Command, []string)
- func WriteErr(api API, ctx Context, status int, msg string, errs ...error) error
- type API
- type Adapter
- type AddOpFunc
- type AutoConfig
- type AutoConfigVar
- type CLI
- type Components
- type Config
- type Contact
- type ContentTypeFilter
- type Context
- type Encoding
- type ErrorDetail
- type ErrorDetailer
- type ErrorModel
- type Example
- type ExternalDocs
- type Format
- type Header
- type Hooks
- type Info
- type License
- type Link
- type MediaType
- type Middlewares
- type ModelValidator
- type OAuthFlow
- type OAuthFlows
- type OpenAPI
- type Operation
- type Param
- type PathBuffer
- type PathItem
- type Registry
- type RequestBody
- type Resolver
- type ResolverWithPath
- type Response
- type Schema
- type SchemaLinkTransformer
- type SchemaProvider
- type SecurityScheme
- type Server
- type ServerVariable
- type StatusError
- func Error400BadRequest(msg string, errs ...error) StatusError
- func Error401Unauthorized(msg string, errs ...error) StatusError
- func Error403Forbidden(msg string, errs ...error) StatusError
- func Error404NotFound(msg string, errs ...error) StatusError
- func Error405MethodNotAllowed(msg string, errs ...error) StatusError
- func Error406NotAcceptable(msg string, errs ...error) StatusError
- func Error409Conflict(msg string, errs ...error) StatusError
- func Error410Gone(msg string, errs ...error) StatusError
- func Error412PreconditionFailed(msg string, errs ...error) StatusError
- func Error415UnsupportedMediaType(msg string, errs ...error) StatusError
- func Error422UnprocessableEntity(msg string, errs ...error) StatusError
- func Error429TooManyRequests(msg string, errs ...error) StatusError
- func Error500InternalServerError(msg string, errs ...error) StatusError
- func Error501NotImplemented(msg string, errs ...error) StatusError
- func Error502BadGateway(msg string, errs ...error) StatusError
- func Error503ServiceUnavailable(msg string, errs ...error) StatusError
- func Error504GatewayTimeout(msg string, errs ...error) StatusError
- func Status304NotModified() StatusError
- type StreamResponse
- type Tag
- type Transformer
- type ValidateMode
- type ValidateResult
Examples ¶
Constants ¶
const ( TypeBoolean = "boolean" TypeInteger = "integer" TypeNumber = "number" TypeString = "string" TypeArray = "array" TypeObject = "object" )
JSON Schema type constants
Variables ¶
var DefaultCBORFormat = Format{ Marshal: func(w io.Writer, v any) error { return cborEncMode.NewEncoder(w).Encode(v) }, Unmarshal: cbor.Unmarshal, }
DefaultCBORFormat is the default CBOR formatter that can be set in the API's `Config.Formats` map. This is used by the `DefaultConfig` function.
config := huma.Config{} config.Formats = map[string]huma.Format{ "application/cbor": huma.DefaultCBORFormat, "cbor": huma.DefaultCBORFormat, }
var DefaultJSONFormat = Format{ Marshal: func(w io.Writer, v any) error { return json.NewEncoder(w).Encode(v) }, Unmarshal: json.Unmarshal, }
DefaultJSONFormat is the default JSON formatter that can be set in the API's `Config.Formats` map. This is used by the `DefaultConfig` function.
config := huma.Config{} config.Formats = map[string]huma.Format{ "application/json": huma.DefaultJSONFormat, "json": huma.DefaultJSONFormat, }
var ErrSchemaInvalid = errors.New("schema is invalid")
ErrSchemaInvalid is sent when there is a problem building the schema.
var NewError = func(status int, msg string, errs ...error) StatusError { details := make([]*ErrorDetail, len(errs)) for i := 0; i < len(errs); i++ { if converted, ok := errs[i].(ErrorDetailer); ok { details[i] = converted.ErrorDetail() } else { details[i] = &ErrorDetail{Message: errs[i].Error()} } } return &ErrorModel{ Status: status, Title: http.StatusText(status), Detail: msg, Errors: details, } }
NewError creates a new instance of an error model with the given status code, message, and optional error details. If the error details implement the `ErrorDetailer` interface, the error details will be used. Otherwise, the error string will be used as the message. This function is used by all the error response utility functions, like `huma.Error400BadRequest`.
Replace this function to use your own error type. Example:
type MyDetail struct { Message string `json:"message"` Location string `json:"location"` } type MyError struct { status int Message string `json:"message"` Errors []error `json:"errors"` } func (e *MyError) Error() string { return e.Message } func (e *MyError) GetStatus() int { return e.status } huma.NewError = func(status int, msg string, errs ...error) StatusError { return &MyError{ status: status, Message: msg, Errors: errs, } }
Functions ¶
func AutoRegister ¶
AutoRegister auto-detects operation registration methods and registers them with the given API. Any method named `Register...` will be called and passed the API as the only argument. Since registration happens at service startup, no errors are returned and methods should panic on error.
type ItemServer struct {} func (s *ItemServer) RegisterListItems(api API) { huma.Register(api, huma.Operation{ OperationID: "ListItems", Method: http.MethodGet, Path: "/items", }, s.ListItems) } func main() { api := huma.NewAPI("My Service", "1.0.0") itemServer := &ItemServer{} huma.AutoRegister(api, itemServer) }
func DefaultSchemaNamer ¶
DefaultSchemaNamer provides schema names for types. It uses the type name when possible, ignoring the package name. If the type is generic, e.g. `MyType[SubType]`, then the brackets are removed like `MyTypeSubType`. If the type is unnamed, then the name hint is used. Note: if you plan to use types with the same name from different packages, you should implement your own namer function to prevent issues. Nested anonymous types can also present naming issues.
func FieldSelectTransform ¶
FieldSelectTransform is an example of a transform that can use an input header value to modify the response on the server, providing a GraphQL-like way to send only the fields that the client wants over the wire.
func Register ¶
Register an operation handler for an API. The handler must be a function that takes a context and a pointer to the input struct and returns a pointer to the output struct and an error. The input struct must be a struct with fields for the request path/query/header parameters and/or body. The output struct must be a struct with fields for the output headers and body of the operation, if any.
func SetReadDeadline ¶
func SetReadDeadline(w http.ResponseWriter, deadline time.Time) error
SetReadDeadline is a utility to set the read deadline on a response writer, if possible. If not, it will not incur any allocations (unlike the stdlib `http.ResponseController`). This is mostly a convenience function for adapters so they can be more efficient.
huma.SetReadDeadline(w, time.Now().Add(5*time.Second))
func Validate ¶
func Validate(r Registry, s *Schema, path *PathBuffer, mode ValidateMode, v any, res *ValidateResult)
Validate an input value against a schema, collecting errors in the validation result object. If successful, `res.Errors` will be empty. It is suggested to use a `sync.Pool` to reuse the PathBuffer and ValidateResult objects, making sure to call `Reset()` on them before returning them to the pool.
registry := huma.NewMapRegistry("#/prefix", huma.DefaultSchemaNamer) schema := huma.SchemaFromType(registry, reflect.TypeOf(MyType{})) pb := huma.NewPathBuffer([]byte(""), 0) res := &huma.ValidateResult{} var value any json.Unmarshal([]byte(`{"foo": "bar"}`), &v) huma.Validate(registry, schema, pb, huma.ModeWriteToServer, value, res) for _, err := range res.Errors { fmt.Println(err.Error()) }
func WithOptions ¶
func WithOptions[Options any](f func(cmd *cobra.Command, args []string, options *Options)) func(*cobra.Command, []string)
WithOptions is a helper for custom commands that need to access the options.
cli.Root().AddCommand(&cobra.Command{ Use: "my-custom-command", Run: huma.WithOptions(func(cmd *cobra.Command, args []string, opts *Options) { fmt.Println("Hello " + opts.Name) }), })
Types ¶
type API ¶
type API interface { // Adapter returns the router adapter for this API, providing a generic // interface to get request information and write responses. Adapter() Adapter // OpenAPI returns the OpenAPI spec for this API. You may edit this spec // until the server starts. OpenAPI() *OpenAPI // Negotiate returns the selected content type given the client's `accept` // header and the server's supported content types. If the client does not // send an `accept` header, then JSON is used. Negotiate(accept string) (string, error) // Marshal marshals the given value into the given writer. The content type // is used to determine which format to use. Use `Negotiate` to get the // content type from an accept header. TODO: update Marshal(ctx Context, respKey string, contentType string, v any) error // Unmarshal unmarshals the given data into the given value. The content type Unmarshal(contentType string, data []byte, v any) error // UseMiddleware appends a middleware handler to the API middleware stack. // // The middleware stack for any API will execute before searching for a matching // route to a specific handler, which provides opportunity to respond early, // change the course of the request execution, or set request-scoped values for // the next Middleware. UseMiddleware(middlewares ...func(ctx Context, next func(Context))) // Middlewares returns a slice of middleware handler functions. Middlewares() Middlewares }
API represents a Huma API wrapping a specific router.
type Adapter ¶
type Adapter interface { Handle(op *Operation, handler func(ctx Context)) ServeHTTP(http.ResponseWriter, *http.Request) }
Adapter is an interface that allows the API to be used with different HTTP routers and frameworks. It is designed to work with the standard library `http.Request` and `http.ResponseWriter` types as well as types like `gin.Context` or `fiber.Ctx` that provide both request and response functionality in one place.
type AutoConfig ¶
type AutoConfig struct { Security string `json:"security"` Headers map[string]string `json:"headers,omitempty"` Prompt map[string]AutoConfigVar `json:"prompt,omitempty"` Params map[string]string `json:"params"` }
AutoConfig holds an API's automatic configuration settings for the CLI. These are advertised via OpenAPI extension and picked up by the CLI to make it easier to get started using an API. This struct should be put into the `OpenAPI.Extensions` map under the key `x-cli-config`. See also: https://rest.sh/#/openapi?id=autoconfiguration
type AutoConfigVar ¶
type AutoConfigVar struct { Description string `json:"description,omitempty"` Example string `json:"example,omitempty"` Default interface{} `json:"default,omitempty"` Enum []interface{} `json:"enum,omitempty"` // Exclude the value from being sent to the server. This essentially makes // it a value which is only used in param templates. Exclude bool `json:"exclude,omitempty"` }
AutoConfigVar represents a variable given by the user when prompted during auto-configuration setup of an API.
type CLI ¶
type CLI interface { // Run the CLI. This will parse the command-line arguments and environment // variables and then run the appropriate command. If no command is given, // the default command will call the `OnStart` function to start a server. Run() // Root returns the root Cobra command. This can be used to add additional // commands or flags. Customize it however you like. Root() *cobra.Command }
CLI is an optional command-line interface for a Huma service. It is provided as a convenience for quickly building a service with configuration from the environment and/or command-line options, all tied to a simple type-safe Go struct.
func NewCLI ¶
NewCLI creates a new CLI. The `onParsed` callback is called after the command options have been parsed and the options struct has been populated. You should set up a `hooks.OnStart` callback to start the server with your chosen router.
// First, define your input options. type Options struct { Debug bool `doc:"Enable debug logging"` Host string `doc:"Hostname to listen on."` Port int `doc:"Port to listen on." short:"p" default:"8888"` } // Then, create the CLI. cli := huma.NewCLI(func(hooks huma.Hooks, opts *Options) { fmt.Printf("Options are debug:%v host:%v port%v\n", opts.Debug, opts.Host, opts.Port) // Set up the router & API router := chi.NewRouter() api := humachi.New(router, huma.DefaultConfig("My API", "1.0.0")) srv := &http.Server{ Addr: fmt.Sprintf("%s:%d", opts.Host, opts.Port), Handler: router, // TODO: Set up timeouts! } hooks.OnStart(func() { if err := srv.ListenAndServe(); err != nil && err != http.ErrServerClosed { log.Fatalf("listen: %s\n", err) } }) hooks.OnStop(func() { srv.Shutdown(context.Background()) }) }) // Run the thing! cli.Run()
type Components ¶
type Components struct { Schemas Registry `yaml:"schemas,omitempty"` Responses map[string]*Response `yaml:"responses,omitempty"` Parameters map[string]*Param `yaml:"parameters,omitempty"` Examples map[string]*Example `yaml:"examples,omitempty"` RequestBodies map[string]*RequestBody `yaml:"requestBodies,omitempty"` Headers map[string]*Header `yaml:"headers,omitempty"` SecuritySchemes map[string]*SecurityScheme `yaml:"securitySchemes,omitempty"` Links map[string]*Link `yaml:"links,omitempty"` Callbacks map[string]*PathItem `yaml:"callbacks,omitempty"` PathItems map[string]*PathItem `yaml:"pathItems,omitempty"` Extensions map[string]any `yaml:",inline"` }
type Config ¶
type Config struct { // OpenAPI spec for the API. You should set at least the `Info.Title` and // `Info.Version` fields. *OpenAPI // OpenAPIPath is the path to the OpenAPI spec without extension. If set // to `/openapi` it will allow clients to get `/openapi.json` or // `/openapi.yaml`, for example. OpenAPIPath string DocsPath string SchemasPath string // Formats defines the supported request/response formats by content type or // extension (e.g. `json` for `application/my-format+json`). Formats map[string]Format // DefaultFormat specifies the default content type to use when the client // does not specify one. If unset, the default type will be randomly // chosen from the keys of `Formats`. DefaultFormat string // Transformers are a way to modify a response body before it is serialized. Transformers []Transformer }
Config represents a configuration for a new API. See `huma.DefaultConfig()` as a starting point.
func DefaultConfig ¶
DefaultConfig returns a default configuration for a new API. It is a good starting point for creating your own configuration. It supports JSON and CBOR formats out of the box. The registry uses references for structs and a link transformer is included to add `$schema` fields and links into responses. The `/openapi.[json|yaml]`, `/docs`, and `/schemas` paths are set up to serve the OpenAPI spec, docs UI, and schemas respectively.
// Create and customize the config (if desired). config := huma.DefaultConfig("My API", "1.0.0") // Create the API using the config. router := chi.NewMux() api := humachi.New(router, config)
type Contact ¶
type Contact struct { // Name of the contact person/organization. Name string `yaml:"name,omitempty"` // URL pointing to the contact information. URL string `yaml:"url,omitempty"` // Email address of the contact person/organization. Email string `yaml:"email,omitempty"` // Extensions (user-defined properties), if any. Values in this map will // be marshalled as siblings of the other properties above. Extensions map[string]any `yaml:",inline"` }
Contact information to get support for the API.
type ContentTypeFilter ¶
ContentTypeFilter allows you to override the content type for responses, allowing you to return a different content type like `application/problem+json` after using the `application/json` marshaller. This should be implemented by the response body struct.
type Context ¶
type Context interface { Operation() *Operation Context() context.Context Method() string Host() string URL() url.URL Param(name string) string Query(name string) string Header(name string) string EachHeader(cb func(name, value string)) BodyReader() io.Reader GetMultipartForm() (*multipart.Form, error) SetReadDeadline(time.Time) error SetStatus(code int) SetHeader(name, value string) AppendHeader(name, value string) BodyWriter() io.Writer }
Context is the current request/response context. It provides a generic interface to get request information and write responses.
type Encoding ¶
type Encoding struct { ContentType string `yaml:"contentType,omitempty"` Headers map[string]*Header `yaml:"headers,omitempty"` Style string `yaml:"style,omitempty"` Explode *bool `yaml:"explode,omitempty"` AllowReserved bool `yaml:"allowReserved,omitempty"` Extensions map[string]any `yaml:",inline"` }
type ErrorDetail ¶
type ErrorDetail struct { // Message is a human-readable explanation of the error. Message string `json:"message,omitempty" doc:"Error message text"` // Location is a path-like string indicating where the error occurred. // It typically begins with `path`, `query`, `header`, or `body`. Example: // `body.items[3].tags` or `path.thing-id`. Location string `json:"location,omitempty" doc:"Where the error occurred, e.g. 'body.items[3].tags' or 'path.thing-id'"` // Value is the value at the given location, echoed back to the client // to help with debugging. This can be useful for e.g. validating that // the client didn't send extra whitespace or help when the client // did not log an outgoing request. Value any `json:"value,omitempty" doc:"The value at the given location"` }
ErrorDetail provides details about a specific error.
func (*ErrorDetail) Error ¶
func (e *ErrorDetail) Error() string
Error returns the error message / satisfies the `error` interface. If a location and value are set, they will be included in the error message, otherwise just the message is returned.
func (*ErrorDetail) ErrorDetail ¶
func (e *ErrorDetail) ErrorDetail() *ErrorDetail
ErrorDetail satisfies the `ErrorDetailer` interface.
type ErrorDetailer ¶
type ErrorDetailer interface {
ErrorDetail() *ErrorDetail
}
ErrorDetailer returns error details for responses & debugging. This enables the use of custom error types. See `NewError` for more details.
type ErrorModel ¶
type ErrorModel struct { // Type is a URI to get more information about the error type. Type string `` /* 170-byte string literal not displayed */ // Title provides a short static summary of the problem. Huma will default this // to the HTTP response status code text if not present. Title string `` /* 166-byte string literal not displayed */ // Status provides the HTTP status code for client convenience. Huma will // default this to the response status code if unset. This SHOULD match the // response status code (though proxies may modify the actual status code). Status int `json:"status,omitempty" example:"400" doc:"HTTP status code"` // Detail is an explanation specific to this error occurrence. Detail string `` /* 153-byte string literal not displayed */ // Instance is a URI to get more info about this error occurrence. Instance string `` /* 163-byte string literal not displayed */ // Errors provides an optional mechanism of passing additional error details // as a list. Errors []*ErrorDetail `json:"errors,omitempty" doc:"Optional list of individual error details"` }
ErrorModel defines a basic error message model based on RFC 7807 Problem Details for HTTP APIs (https://datatracker.ietf.org/doc/html/rfc7807). It is augmented with an `errors` field of `huma.ErrorDetail` objects that can help provide exhaustive & descriptive errors.
err := &huma.ErrorModel{ Title: http.StatusText(http.StatusBadRequest), Status http.StatusBadRequest, Detail: "Validation failed", Errors: []*huma.ErrorDetail{ &huma.ErrorDetail{ Message: "expected required property id to be present", Location: "body.friends[0]", Value: nil, }, &huma.ErrorDetail{ Message: "expected boolean", Location: "body.friends[1].active", Value: 5, }, }, }
func (*ErrorModel) Add ¶
func (e *ErrorModel) Add(err error)
Add an error to the `Errors` slice. If passed a struct that satisfies the `huma.ErrorDetailer` interface, then it is used, otherwise the error string is used as the error detail message.
err := &ErrorModel{ /* ... */ } err.Add(&huma.ErrorDetail{ Message: "expected boolean", Location: "body.friends[1].active", Value: 5 })
func (*ErrorModel) ContentType ¶
func (e *ErrorModel) ContentType(ct string) string
ContentType provides a filter to adjust response content types. This is used to ensure e.g. `application/problem+json` content types defined in RFC 7807 Problem Details for HTTP APIs are used in responses to clients.
func (*ErrorModel) Error ¶
func (e *ErrorModel) Error() string
Error satisfies the `error` interface. It returns the error's detail field.
func (*ErrorModel) GetStatus ¶
func (e *ErrorModel) GetStatus() int
GetStatus returns the HTTP status that should be returned to the client for this error.
type ExternalDocs ¶
type Format ¶
type Format struct { // Marshal a value to a given writer (e.g. response body). Marshal func(writer io.Writer, v any) error // Unmarshal a value into `v` from the given bytes (e.g. request body). Unmarshal func(data []byte, v any) error }
Format represents a request / response format. It is used to marshal and unmarshal data.
type Hooks ¶
type Hooks interface { // OnStart sets a function to call when the service should be started. This // is called by the default command if no command is given. The callback // should take whatever steps are necessary to start the server, such as // `httpServer.ListenAndServer(...)`. OnStart(func()) // OnStop sets a function to call when the service should be stopped. This // is called by the default command if no command is given. The callback // should take whatever steps are necessary to stop the server, such as // `httpServer.Shutdown(...)`. OnStop(func()) }
Hooks is an interface for setting up callbacks for the CLI. It is used to start and stop the service.
type Info ¶
type Info struct { // Title of the API. Title string `yaml:"title"` // Description of the API. CommonMark syntax MAY be used for rich text representation. Description string `yaml:"description,omitempty"` // TermsOfService URL for the API. TermsOfService string `yaml:"termsOfService,omitempty"` // Contact information to get support for the API. Contact *Contact `yaml:"contact,omitempty"` // License name & link for using the API. License *License `yaml:"license,omitempty"` // Version of the OpenAPI document (which is distinct from the OpenAPI Specification version or the API implementation version). Version string `yaml:"version"` // Extensions (user-defined properties), if any. Values in this map will // be marshalled as siblings of the other properties above. Extensions map[string]any `yaml:",inline"` }
Info object that provides metadata about the API. The metadata MAY be used by the clients if needed, and MAY be presented in editing or documentation generation tools for convenience.
type License ¶
type License struct { // Name of the license. Name string `yaml:"name"` // Identifier SPDX license expression for the API. This field is mutually // exclusive with the URL field. Identifier string `yaml:"identifier,omitempty"` // URL pointing to the license. This field is mutually exclusive with the // Identifier field. URL string `yaml:"url,omitempty"` // Extensions (user-defined properties), if any. Values in this map will // be marshalled as siblings of the other properties above. Extensions map[string]any `yaml:",inline"` }
License name & link for using the API.
type Link ¶
type Link struct { Ref string `yaml:"$ref,omitempty"` OperationRef string `yaml:"operationRef,omitempty"` OperationID string `yaml:"operationId,omitempty"` Parameters map[string]any `yaml:"parameters,omitempty"` RequestBody any `yaml:"requestBody,omitempty"` Description string `yaml:"description,omitempty"` Server *Server `yaml:"server,omitempty"` Extensions map[string]any `yaml:",inline"` }
type Middlewares ¶
func (Middlewares) Handler ¶
func (m Middlewares) Handler(endpoint func(Context)) func(Context)
Handler builds and returns a handler func from the chain of middlewares, with `endpoint func` as the final handler.
type ModelValidator ¶
type ModelValidator struct {
// contains filtered or unexported fields
}
ModelValidator is a utility for validating e.g. JSON loaded data against a Go struct model. It is not goroutine-safe and should not be used in HTTP handlers! Schemas are generated on-the-fly on first use and re-used on subsequent calls. This utility can be used to easily validate data outside of the normal request/response flow, for example on application startup:
type MyExample struct { Name string `json:"name" maxLength:"5"` Age int `json:"age" minimum:"25"` } var value any json.Unmarshal([]byte(`{"name": "abcdefg", "age": 1}`), &value) validator := ModelValidator() errs := validator.Validate(reflect.TypeOf(MyExample{}), value) if errs != nil { fmt.Println("Validation error", errs) }
Example ¶
// Define a type you want to validate. type Model struct { Name string `json:"name" maxLength:"5"` Age int `json:"age" minimum:"25"` } typ := reflect.TypeOf(Model{}) // Unmarshal some JSON into an `any` for validation. This input should not // validate against the schema for the struct above. var val any json.Unmarshal([]byte(`{"name": "abcdefg", "age": 1}`), &val) // Validate the unmarshaled data against the type and print errors. validator := NewModelValidator() errs := validator.Validate(typ, val) fmt.Println(errs) // Try again with valid data! json.Unmarshal([]byte(`{"name": "foo", "age": 25}`), &val) errs = validator.Validate(typ, val) fmt.Println(errs)
Output: [expected length <= 5 (name: abcdefg) expected number >= 25 (age: 1)] []
func NewModelValidator ¶
func NewModelValidator() *ModelValidator
NewModelValidator creates a new model validator with all the components it needs to create schemas, validate them, and return any errors.
func (*ModelValidator) Validate ¶
func (v *ModelValidator) Validate(typ reflect.Type, value any) []error
Validate the inputs. The type should be the Go struct with validation field tags and the value should be e.g. JSON loaded into an `any`. A list of errors is returned if validation failed, otherwise `nil`.
type MyExample struct { Name string `json:"name" maxLength:"5"` Age int `json:"age" minimum:"25"` } var value any json.Unmarshal([]byte(`{"name": "abcdefg", "age": 1}`), &value) validator := ModelValidator() errs := validator.Validate(reflect.TypeOf(MyExample{}), value) if errs != nil { fmt.Println("Validation error", errs) }
type OAuthFlows ¶
type OpenAPI ¶
type OpenAPI struct { OpenAPI string `yaml:"openapi"` Info *Info `yaml:"info"` Servers []*Server `yaml:"servers,omitempty"` JSONSchemaDialect string `yaml:"jsonSchemaDialect,omitempty"` Paths map[string]*PathItem `yaml:"paths,omitempty"` Webhooks map[string]*PathItem `yaml:"webhooks,omitempty"` Components *Components `yaml:"components,omitempty"` Security []map[string][]string `yaml:"security,omitempty"` Tags []*Tag `yaml:"tags,omitempty"` ExternalDocs *ExternalDocs `yaml:"externalDocs,omitempty"` Extensions map[string]any `yaml:",inline"` // OnAddOperation is called when an operation is added to the OpenAPI via // `AddOperation`. You may bypass this by directly writing to the `Paths` // map instead. OnAddOperation []AddOpFunc `yaml:"-"` }
func (*OpenAPI) AddOperation ¶
func (*OpenAPI) MarshalJSON ¶
type Operation ¶
type Operation struct { // Method is the HTTP method for this operation Method string `yaml:"-"` // Path is the URL path for this operation Path string `yaml:"-"` // DefaultStatus is the default HTTP status code for this operation. It will // be set to 200 or 204 if not specified, depending on whether the handler // returns a response body. DefaultStatus int `yaml:"-"` // MaxBodyBytes is the maximum number of bytes to read from the request // body. If not specified, the default is 1MB. Use -1 for unlimited. If // the limit is reached, then an HTTP 413 error is returned. MaxBodyBytes int64 `yaml:"-"` // BodyReadTimeout is the maximum amount of time to wait for the request // body to be read. If not specified, the default is 5 seconds. Use -1 // for unlimited. If the timeout is reached, then an HTTP 408 error is // returned. This value supercedes the server's read timeout, and a value // of -1 can unset the server's timeout. BodyReadTimeout time.Duration `yaml:"-"` // Errors is a list of HTTP status codes that the handler may return. If // not specified, then a default error response is added to the OpenAPI. Errors []int `yaml:"-"` // SkipValidateParams disables validation of path, query, and header // parameters. This can speed up request processing if you want to handle // your own validation. Use with caution! SkipValidateParams bool `yaml:"-"` // SkipValidateBody disables validation of the request body. This can speed // up request processing if you want to handle your own validation. Use with // caution! SkipValidateBody bool `yaml:"-"` // Hidden will skip documenting this operation in the OpenAPI. This is // useful for operations that are not intended to be used by clients but // you'd still like the benefits of using Huma. Generally not recommended. Hidden bool `yaml:"-"` Tags []string `yaml:"tags,omitempty"` Summary string `yaml:"summary,omitempty"` Description string `yaml:"description,omitempty"` ExternalDocs *ExternalDocs `yaml:"externalDocs,omitempty"` OperationID string `yaml:"operationId,omitempty"` Parameters []*Param `yaml:"parameters,omitempty"` RequestBody *RequestBody `yaml:"requestBody,omitempty"` Responses map[string]*Response `yaml:"responses,omitempty"` Callbacks map[string]*PathItem `yaml:"callbacks,omitempty"` Deprecated bool `yaml:"deprecated,omitempty"` Security []map[string][]string `yaml:"security,omitempty"` Servers []*Server `yaml:"servers,omitempty"` Extensions map[string]any `yaml:",inline"` }
type Param ¶
type Param struct { Ref string `yaml:"$ref,omitempty"` Name string `yaml:"name,omitempty"` In string `yaml:"in,omitempty"` Description string `yaml:"description,omitempty"` Required bool `yaml:"required,omitempty"` Deprecated bool `yaml:"deprecated,omitempty"` Style string `yaml:"style,omitempty"` Explode *bool `yaml:"explode,omitempty"` AllowReserved bool `yaml:"allowReserved,omitempty"` Schema *Schema `yaml:"schema,omitempty"` Example any `yaml:"example,omitempty"` Examples map[string]*Example `yaml:"examples,omitempty"` Extensions map[string]any `yaml:",inline"` }
type PathBuffer ¶
type PathBuffer struct {
// contains filtered or unexported fields
}
PathBuffer is a low-allocation helper for building a path string like `foo.bar.baz`. It is not goroutine-safe. Combined with `sync.Pool` it can result in zero allocations, and is used for validation. It is significantly better than `strings.Builder` and `bytes.Buffer` for this use case.
Path buffers can be converted to strings for use in responses or printing using either the `pb.String()` or `pb.With("field")` methods.
pb := NewPathBuffer([]byte{}, 0) pb.Push("foo") // foo pb.PushIndex(1) // foo[1] pb.Push("bar") // foo[1].bar pb.Pop() // foo[1] pb.Pop() // foo
func NewPathBuffer ¶
func NewPathBuffer(buf []byte, offset int) *PathBuffer
NewPathBuffer creates a new path buffer given an existing byte slice. Tip: using `sync.Pool` can significantly reduce buffer allocations.
pb := NewPathBuffer([]byte{}, 0) pb.Push("foo")
func (*PathBuffer) Bytes ¶
func (b *PathBuffer) Bytes() []byte
Bytes returns the underlying slice of bytes of the path.
func (*PathBuffer) Pop ¶
func (b *PathBuffer) Pop()
Pop the latest entry off the path.
pb.Push("foo") // foo pb.PushIndex(1) // foo[1] pb.Push("bar") // foo[1].bar pb.Pop() // foo[1] pb.Pop() // foo
func (*PathBuffer) Push ¶
func (b *PathBuffer) Push(s string)
Push an entry onto the path, adding a `.` separator as needed.
pb.Push("foo") // foo pb.Push("bar") // foo.bar
func (*PathBuffer) PushIndex ¶
func (b *PathBuffer) PushIndex(i int)
PushIndex pushes an entry onto the path surrounded by `[` and `]`.
pb.Push("foo") // foo pb.PushIndex(1) // foo[1]
func (*PathBuffer) Reset ¶
func (b *PathBuffer) Reset()
Reset the path buffer to empty, keeping and reusing the underlying bytes.
func (*PathBuffer) String ¶
func (b *PathBuffer) String() string
String converts the path buffer to a string.
func (*PathBuffer) With ¶
func (b *PathBuffer) With(s string) string
With is shorthand for push, convert to string, and pop. This is useful when you want the location of a field given a path buffer as a prefix.
pb.Push("foo") pb.With("bar") // returns foo.bar
type PathItem ¶
type PathItem struct { Ref string `yaml:"$ref,omitempty"` Summary string `yaml:"summary,omitempty"` Description string `yaml:"description,omitempty"` Get *Operation `yaml:"get,omitempty"` Put *Operation `yaml:"put,omitempty"` Post *Operation `yaml:"post,omitempty"` Delete *Operation `yaml:"delete,omitempty"` Options *Operation `yaml:"options,omitempty"` Head *Operation `yaml:"head,omitempty"` Patch *Operation `yaml:"patch,omitempty"` Trace *Operation `yaml:"trace,omitempty"` Servers []*Server `yaml:"servers,omitempty"` Parameters []*Param `yaml:"parameters,omitempty"` Extensions map[string]any `yaml:",inline"` }
type Registry ¶
type Registry interface { Schema(t reflect.Type, allowRef bool, hint string) *Schema SchemaFromRef(ref string) *Schema TypeFromRef(ref string) reflect.Type Map() map[string]*Schema }
Registry creates and stores schemas and their references, and supports marshalling to JSON/YAML for use as an OpenAPI #/components/schemas object. Behavior is implementation-dependent, but the design allows for recursive schemas to exist while being flexible enough to support other use cases like only inline objects (no refs) or always using refs for structs.
type RequestBody ¶
type Resolver ¶
Resolver runs a `Resolve` function after a request has been parsed, enabling you to run custom validation or other code that can modify the request and / or return errors.
type ResolverWithPath ¶
type ResolverWithPath interface {
Resolve(ctx Context, prefix *PathBuffer) []error
}
ResolverWithPath runs a `Resolve` function after a request has been parsed, enabling you to run custom validation or other code that can modify the request and / or return errors. The `prefix` is the path to the current location for errors, e.g. `body.foo[0].bar`.
type Response ¶
type Response struct { Ref string `yaml:"$ref,omitempty"` Description string `yaml:"description,omitempty"` Headers map[string]*Param `yaml:"headers,omitempty"` Content map[string]*MediaType `yaml:"content,omitempty"` Links map[string]*Link `yaml:"links,omitempty"` Extensions map[string]any `yaml:",inline"` }
type Schema ¶
type Schema struct { Type string `yaml:"type,omitempty"` Title string `yaml:"title,omitempty"` Description string `yaml:"description,omitempty"` Ref string `yaml:"$ref,omitempty"` Format string `yaml:"format,omitempty"` ContentEncoding string `yaml:"contentEncoding,omitempty"` Default any `yaml:"default,omitempty"` Examples []any `yaml:"examples,omitempty"` Items *Schema `yaml:"items,omitempty"` AdditionalProperties any `yaml:"additionalProperties,omitempty"` Properties map[string]*Schema `yaml:"properties,omitempty"` Enum []any `yaml:"enum,omitempty"` Minimum *float64 `yaml:"minimum,omitempty"` ExclusiveMinimum *float64 `yaml:"exclusiveMinimum,omitempty"` Maximum *float64 `yaml:"maximum,omitempty"` ExclusiveMaximum *float64 `yaml:"exclusiveMaximum,omitempty"` MultipleOf *float64 `yaml:"multipleOf,omitempty"` MinLength *int `yaml:"minLength,omitempty"` MaxLength *int `yaml:"maxLength,omitempty"` Pattern string `yaml:"pattern,omitempty"` MinItems *int `yaml:"minItems,omitempty"` MaxItems *int `yaml:"maxItems,omitempty"` UniqueItems bool `yaml:"uniqueItems,omitempty"` Required []string `yaml:"required,omitempty"` MinProperties *int `yaml:"minProperties,omitempty"` MaxProperties *int `yaml:"maxProperties,omitempty"` ReadOnly bool `yaml:"readOnly,omitempty"` WriteOnly bool `yaml:"writeOnly,omitempty"` Deprecated bool `yaml:"deprecated,omitempty"` Extensions map[string]any `yaml:",inline"` OneOf []*Schema `yaml:"oneOf,omitempty"` AnyOf []*Schema `yaml:"anyOf,omitempty"` AllOf []*Schema `yaml:"allOf,omitempty"` Not *Schema `yaml:"not,omitempty"` // contains filtered or unexported fields }
Schema represents a JSON Schema compatible with OpenAPI 3.1. It is extensible with your own custom properties. It supports a subset of the full JSON Schema spec, designed specifically for use with Go structs and to enable fast zero or near-zero allocation happy-path validation for incoming requests.
Typically you will use a registry and `huma.SchemaFromType` to generate schemas for your types. You can then use `huma.Validate` to validate incoming requests.
// Create a registry and register a type. registry := huma.NewMapRegistry("#/prefix", huma.DefaultSchemaNamer) schema := huma.SchemaFromType(registry, reflect.TypeOf(MyType{}))
Note that the registry may create references for your types.
func SchemaFromField ¶
func SchemaFromField(registry Registry, f reflect.StructField, hint string) *Schema
SchemaFromField generates a schema for a given struct field. If the field is a struct (or slice/map of structs) then the registry is used to potentially get a reference to that type.
This is used by `huma.SchemaFromType` when it encounters a struct, and is used to generate schemas for path/query/header parameters.
func SchemaFromType ¶
SchemaFromType returns a schema for a given type, using the registry to possibly create references for nested structs. The schema that is returned can then be passed to `huma.Validate` to efficiently validate incoming requests.
// Create a registry and register a type. registry := huma.NewMapRegistry("#/prefix", huma.DefaultSchemaNamer) schema := huma.SchemaFromType(registry, reflect.TypeOf(MyType{}))
func (*Schema) MarshalJSON ¶
MarshalJSON marshals the schema into JSON, respecting the `Extensions` map to marshal extensions inline.
func (*Schema) PrecomputeMessages ¶
func (s *Schema) PrecomputeMessages()
PrecomputeMessages tries to precompute as many validation error messages as possible so that new strings aren't allocated during request validation.
type SchemaLinkTransformer ¶
type SchemaLinkTransformer struct {
// contains filtered or unexported fields
}
SchemaLinkTransformer is a transform that adds a `$schema` field to the response (if it is a struct) and a Link header pointing to the JSON Schema that describes the response structure. This is useful for clients to understand the structure of the response and enables things like as-you-type validation & completion of HTTP resources in editors like VSCode.
func NewSchemaLinkTransformer ¶
func NewSchemaLinkTransformer(prefix, schemasPath string) *SchemaLinkTransformer
NewSchemaLinkTransformer creates a new transformer that will add a `$schema` field to the response (if it is a struct) and a Link header pointing to the JSON Schema that describes the response structure. This is useful for clients to understand the structure of the response and enables things like as-you-type validation & completion of HTTP resources in editors like VSCode.
func (*SchemaLinkTransformer) OnAddOperation ¶
func (t *SchemaLinkTransformer) OnAddOperation(oapi *OpenAPI, op *Operation)
OnAddOperation is triggered whenever a new operation is added to the API, enabling this transformer to precompute & cache information about the response and schema.
type SchemaProvider ¶
SchemaProvider is an interface that can be implemented by types to provide a custom schema for themselves, overriding the built-in schema generation. This can be used by custom types with their own special serialization rules.
type SecurityScheme ¶
type SecurityScheme struct { Type string `yaml:"type"` Description string `yaml:"description,omitempty"` Name string `yaml:"name,omitempty"` In string `yaml:"in,omitempty"` Scheme string `yaml:"scheme,omitempty"` BearerFormat string `yaml:"bearerFormat,omitempty"` Flows *OAuthFlows `yaml:"flows,omitempty"` OpenIDConnectURL string `yaml:"openIdConnectUrl,omitempty"` Extensions map[string]any `yaml:",inline"` }
type Server ¶
type Server struct { // URL to the target host. This URL supports Server Variables and MAY be relative, to indicate that the host location is relative to the location where the OpenAPI document is being served. Variable substitutions will be made when a variable is named in {brackets}. URL string `yaml:"url"` // Description of the host designated by the URL. CommonMark syntax MAY be used for rich text representation. Description string `yaml:"description,omitempty"` // Variables map between a variable name and its value. The value is used for substitution in the server’s URL template. Variables map[string]*ServerVariable `yaml:"variables,omitempty"` // Extensions (user-defined properties), if any. Values in this map will // be marshalled as siblings of the other properties above. Extensions map[string]any `yaml:",inline"` }
Server URL, optionally with variables.
type ServerVariable ¶
type ServerVariable struct { // Enumeration of string values to be used if the substitution options are from a limited set. The array MUST NOT be empty. Enum []string `yaml:"enum,omitempty"` // Default value to use for substitution, which SHALL be sent if an alternate value is not supplied. Default string `yaml:"default"` // Description for the server variable. CommonMark syntax MAY be used for rich text representation. Description string `yaml:"description,omitempty"` // Extensions (user-defined properties), if any. Values in this map will // be marshalled as siblings of the other properties above. Extensions map[string]any `yaml:",inline"` }
ServerVariable for server URL template substitution.
type StatusError ¶
StatusError is an error that has an HTTP status code. When returned from an operation handler, this sets the response status code before sending it to the client.
func Error400BadRequest ¶
func Error400BadRequest(msg string, errs ...error) StatusError
Error400BadRequest returns a 400.
func Error401Unauthorized ¶
func Error401Unauthorized(msg string, errs ...error) StatusError
Error401Unauthorized returns a 401.
func Error403Forbidden ¶
func Error403Forbidden(msg string, errs ...error) StatusError
Error403Forbidden returns a 403.
func Error404NotFound ¶
func Error404NotFound(msg string, errs ...error) StatusError
Error404NotFound returns a 404.
func Error405MethodNotAllowed ¶
func Error405MethodNotAllowed(msg string, errs ...error) StatusError
Error405MethodNotAllowed returns a 405.
func Error406NotAcceptable ¶
func Error406NotAcceptable(msg string, errs ...error) StatusError
Error406NotAcceptable returns a 406.
func Error409Conflict ¶
func Error409Conflict(msg string, errs ...error) StatusError
Error409Conflict returns a 409.
func Error410Gone ¶
func Error410Gone(msg string, errs ...error) StatusError
Error410Gone returns a 410.
func Error412PreconditionFailed ¶
func Error412PreconditionFailed(msg string, errs ...error) StatusError
Error412PreconditionFailed returns a 412.
func Error415UnsupportedMediaType ¶
func Error415UnsupportedMediaType(msg string, errs ...error) StatusError
Error415UnsupportedMediaType returns a 415.
func Error422UnprocessableEntity ¶
func Error422UnprocessableEntity(msg string, errs ...error) StatusError
Error422UnprocessableEntity returns a 422.
func Error429TooManyRequests ¶
func Error429TooManyRequests(msg string, errs ...error) StatusError
Error429TooManyRequests returns a 429.
func Error500InternalServerError ¶
func Error500InternalServerError(msg string, errs ...error) StatusError
Error500InternalServerError returns a 500.
func Error501NotImplemented ¶
func Error501NotImplemented(msg string, errs ...error) StatusError
Error501NotImplemented returns a 501.
func Error502BadGateway ¶
func Error502BadGateway(msg string, errs ...error) StatusError
Error502BadGateway returns a 502.
func Error503ServiceUnavailable ¶
func Error503ServiceUnavailable(msg string, errs ...error) StatusError
Error503ServiceUnavailable returns a 503.
func Error504GatewayTimeout ¶
func Error504GatewayTimeout(msg string, errs ...error) StatusError
Error504GatewayTimeout returns a 504.
func Status304NotModified ¶
func Status304NotModified() StatusError
Status304NotModified returns a 304. This is not really an error, but provides a way to send non-default responses.
type StreamResponse ¶
type StreamResponse struct {
Body func(ctx Context)
}
StreamResponse is a response that streams data to the client. The body function will be called once the response headers have been written and the body writer is ready to be written to.
func handler(ctx context.Context, input *struct{}) (*huma.StreamResponse, error) { return &huma.StreamResponse{ Body: func(ctx huma.Context) { ctx.SetHeader("Content-Type", "text/my-type") // Write some data to the stream. writer := ctx.BodyWriter() writer.Write([]byte("Hello ")) // Flush the stream to the client. if f, ok := writer.(http.Flusher); ok { f.Flush() } // Write some more... writer.Write([]byte("world!")) } } }
type Tag ¶
type Tag struct { Name string `yaml:"name"` Description string `yaml:"description,omitempty"` ExternalDocs *ExternalDocs `yaml:"externalDocs,omitempty"` Extensions map[string]any `yaml:",inline"` }
type Transformer ¶
Transformer is a function that can modify a response body before it is serialized. The `status` is the HTTP status code for the response and `v` is the value to be serialized. The return value is the new value to be serialized or an error.
type ValidateMode ¶
type ValidateMode int
ValidateMode describes the direction of validation (server -> client or client -> server). It impacts things like how read-only or write-only fields are handled.
const ( // ModeReadFromServer is a read mode (response output) that may ignore or // reject write-only fields that are non-zero, as these write-only fields // are meant to be sent by the client. ModeReadFromServer ValidateMode = iota // ModeWriteToServer is a write mode (request input) that may ignore or // reject read-only fields that are non-zero, as these are owned by the // server and the client should not try to modify them. ModeWriteToServer )
type ValidateResult ¶
type ValidateResult struct {
Errors []error
}
ValidateResult tracks validation errors. It is safe to use for multiple validations as long as `Reset()` is called between uses.
func (*ValidateResult) Add ¶
func (r *ValidateResult) Add(path *PathBuffer, v any, msg string)
Add an error to the validation result at the given path and with the given value.
func (*ValidateResult) Addf ¶
func (r *ValidateResult) Addf(path *PathBuffer, v any, format string, args ...any)
Addf adds an error to the validation result at the given path and with the given value, allowing for fmt.Printf-style formatting.
func (*ValidateResult) Reset ¶
func (r *ValidateResult) Reset()
Reset the validation error so it can be used again.
Source Files
¶
Directories
¶
Path | Synopsis |
---|---|
adapters
|
|
examples
|
|
omit
This example shows how to handle omittable/nullable fields and an optional body in JSON input.
|
This example shows how to handle omittable/nullable fields and an optional body in JSON input. |
oneof-response
This example show how to respond to API requests with different versions of the response body.
|
This example show how to respond to API requests with different versions of the response body. |
param-reuse
This example shows how to reuse a parameter in the path and body.
|
This example shows how to reuse a parameter in the path and body. |
v1-middleware
An example showing how to use Huma v1 middleware in a Huma v2 project.
|
An example showing how to use Huma v1 middleware in a Huma v2 project. |
Package humatest provides testing utilities for Huma services.
|
Package humatest provides testing utilities for Huma services. |
Package queryparam provides utilities for efficiently working with query parameters in URLs.
|
Package queryparam provides utilities for efficiently working with query parameters in URLs. |
Package sse provides utilities for working with Server Sent Events (SSE).
|
Package sse provides utilities for working with Server Sent Events (SSE). |