## File: README.md

<a href="#">
	
		
		
		
	
</a>

[](https://huma.rocks/) [](https://github.com/danielgtaylor/huma/actions?query=workflow%3ACI+branch%3Amain++) [](https://codecov.io/gh/danielgtaylor/huma) [](https://pkg.go.dev/github.com/danielgtaylor/huma/v2?tab=doc) [](https://goreportcard.com/report/github.com/danielgtaylor/huma/v2)

[**🌎中文文档**](./README_CN.md)
[**🇯🇵日本語ドキュメント**](./README_JA.md)

- [What is huma?](#intro)
- [Install](#install)
- [Example](#example)
- [Documentation](#documentation)

<a name="intro"></a>
A modern, simple, fast & flexible micro framework for building HTTP REST/RPC APIs in Go backed by OpenAPI 3 and JSON Schema. Pronounced IPA: [/'hjuːmɑ/](https://en.wiktionary.org/wiki/Wiktionary:International_Phonetic_Alphabet). The goals of this project are to provide:

- Incremental adoption for teams with existing services
  - Bring your own router (including Go 1.22+), middleware, and logging/metrics
  - Extensible OpenAPI & JSON Schema layer to document existing routes
- A modern REST or HTTP RPC API backend framework for Go developers
  - Described by [OpenAPI 3.1](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.1.0.md) & [JSON Schema](https://json-schema.org/)
- Guard rails to prevent common mistakes
- Documentation that can't get out of date
- High-quality generated developer tooling

Features include:

- Declarative interface on top of your router of choice:
  - Operation & model documentation
  - Request params (path, query, header, or cookie)
  - Request body
  - Responses (including errors)
  - Response headers
- JSON Errors using [RFC9457](https://datatracker.ietf.org/doc/html/rfc9457) and `application/problem+json` by default (but can be changed)
- Per-operation request size limits with sane defaults
- [Content negotiation](https://developer.mozilla.org/en-US/docs/Web/HTTP/Content_negotiation) between server and client
  - Support for JSON ([RFC 8259](https://tools.ietf.org/html/rfc8259)) and optionally CBOR ([RFC 7049](https://tools.ietf.org/html/rfc7049)) content types via the `Accept` header with the default config.
- Conditional requests support, e.g. `If-Match` or `If-Unmodified-Since` header utilities.
- Optional automatic generation of `PATCH` operations that support:
  - [RFC 7386](https://www.rfc-editor.org/rfc/rfc7386) JSON Merge Patch
  - [RFC 6902](https://www.rfc-editor.org/rfc/rfc6902) JSON Patch
  - [Shorthand](https://github.com/danielgtaylor/shorthand) patches
- Annotated Go types for input and output models
  - Generates JSON Schema from Go types
  - Static typing for path/query/header params, bodies, response headers, etc.
  - Automatic input model validation & error handling
- Documentation generation using [Stoplight Elements](https://stoplight.io/open-source/elements)
- Optional CLI built-in, configured via arguments or environment variables
  - Set via e.g. `-p 8000`, `--port=8000`, or `SERVICE_PORT=8000`
  - Startup actions & graceful shutdown built-in
- Generates OpenAPI for access to a rich ecosystem of tools
  - Mocks with [API Sprout](https://github.com/danielgtaylor/apisprout) or [Prism](https://stoplight.io/open-source/prism)
  - SDKs with [OpenAPI Generator](https://github.com/OpenAPITools/openapi-generator) or [oapi-codegen](https://github.com/deepmap/oapi-codegen)
  - CLI with [Restish](https://rest.sh/)
  - And [plenty](https://openapi.tools/) [more](https://apis.guru/awesome-openapi3/category.html)
- Generates JSON Schema for each resource using optional `describedby` link relation headers as well as optional `$schema` properties in returned objects that integrate into editors for validation & completion.

This project was inspired by [FastAPI](https://fastapi.tiangolo.com/). Logo & branding designed by Kari Taylor.

## Sponsors

A big thank you to our current & former sponsors!


	<a href="https://serpapi.com/?utm_source=huma">
		
	</a>
	<h3>SerpApi: Web Search API</h3>
	
		Access Google Search, Maps, Shopping, and other search engine data with a simple API by SerpApi.
	
	[Learn more](https://serpapi.com/?utm_source=huma)

<hr/>

- [@bclements](https://github.com/bclements)
- [@bekabaz](https://github.com/bekabaz)
- [@victoraugustolls](https://github.com/victoraugustolls)
- [@phoenixtechnologies-io](https://github.com/phoenixtechnologies-io)
- [@chenjr0719](https://github.com/chenjr0719)
- [@vinogradovkonst](https://github.com/vinogradovkonst)
- [@miyamo2](https://github.com/miyamo2)
- [@nielskrijger](https://github.com/nielskrijger)

## Testimonials

> This is by far my favorite web framework for Go. It is inspired by FastAPI, which is also amazing, and conforms to many RFCs for common web things ... I really like the feature set, the fact that it [can use] Chi, and the fact that it is still somehow relatively simple to use. I've tried other frameworks and they do not spark joy for me. - [Jeb_Jenky](https://www.reddit.com/r/golang/comments/zhitcg/comment/izmg6vk/?utm_source=reddit&utm_medium=web2x&context=3)

> After working with #Golang for over a year, I stumbled upon Huma, the #FastAPI-inspired web framework. It’s the Christmas miracle I’ve been hoping for! This framework has everything! - [Hana Mohan](https://twitter.com/unamashana/status/1733088066053583197)

> I love Huma. Thank you, sincerely, for this awesome package. I’ve been using it for some time now and it’s been great! - [plscott](https://www.reddit.com/r/golang/comments/1aoshey/comment/kq6hcpd/?utm_source=reddit&utm_medium=web2x&context=3)

> Thank you Daniel for Huma. Superbly useful project and saves us a lot of time and hassle thanks to the OpenAPI gen — similar to FastAPI in Python. - [WolvesOfAllStreets](https://www.reddit.com/r/golang/comments/1aqj99d/comment/kqfqcml/?utm_source=reddit&utm_medium=web2x&context=3)

> Huma is wonderful, I've started working with it recently, and it's a pleasure, so thank you very much for your efforts 🙏 - [callmemicah](https://www.reddit.com/r/golang/comments/1b32ts4/comment/ksvr9h7/?utm_source=reddit&utm_medium=web2x&context=3)

> It took us 3 months to build our platform in Python with FastAPI, SQL Alchemy and only 3 weeks to rewrite it in Go with Huma and SQL C. Things just work and I seldomly have to debug where in Python I spent a majority of my time debugging. - [Bitclick\_](https://www.reddit.com/r/golang/comments/1cj2znb/comment/l2e4u6y/)

> Look at Huma, it's great. A nice slim layer on top of stdlib mux/chi and automatic body and parameter serialization, kinda feels like doing dotnet web APIs, but forces you to actually design request and response structs, which is great imo. - [Kirides](https://www.reddit.com/r/golang/comments/1fnn5c2/comment/lokuvpo/)

# Install

Install via `go get`. Note that Go 1.25 or newer is required.

```sh
# After: go mod init ...
go get -u github.com/danielgtaylor/huma/v2
```

# Example

Here is a complete basic hello world example in Huma, that shows how to initialize a Huma app complete with CLI, declare a resource operation, and define its handler function.

```go
package main

import (
	"context"
	"fmt"
	"net/http"

	"github.com/danielgtaylor/huma/v2"
	"github.com/danielgtaylor/huma/v2/adapters/humachi"
	"github.com/danielgtaylor/huma/v2/humacli"
	"github.com/go-chi/chi/v5"

	_ "github.com/danielgtaylor/huma/v2/formats/cbor"
)

// Options for the CLI. Pass `--port` or set the `SERVICE_PORT` env var.
type Options struct {
	Port int `help:"Port to listen on" short:"p" default:"8888"`
}

// GreetingOutput represents the greeting operation response.
type GreetingOutput struct {
	Body struct {
		Message string `json:"message" example:"Hello, world!" doc:"Greeting message"`
	}
}

func main() {
	// Create a CLI app which takes a port option.
	cli := humacli.New(func(hooks humacli.Hooks, options *Options) {
		// Create a new router & API
		router := chi.NewMux()
		api := humachi.New(router, huma.DefaultConfig("My API", "1.0.0"))

		// Add the operation handler to the API.
		huma.Get(api, "/greeting/{name}", func(ctx context.Context, input *struct{
			Name string `path:"name" maxLength:"30" example:"world" doc:"Name to greet"`
		}) (*GreetingOutput, error) {
			resp := &GreetingOutput{}
			resp.Body.Message = fmt.Sprintf("Hello, %s!", input.Name)
			return resp, nil
		})

		// Tell the CLI how to start your router.
		hooks.OnStart(func() {
			http.ListenAndServe(fmt.Sprintf(":%d", options.Port), router)
		})
	})

	// Run the CLI. When passed no commands, it starts the server.
	cli.Run()
}
```

> [!TIP]
> Replace `chi.NewMux()` → `http.NewServeMux()` and `humachi.New` → `humago.New` to use the standard library router from Go 1.22+. Just make sure your `go.mod` has `go 1.22` or newer listed in it. Everything else stays the same! Switch whenever you are ready.

You can test it with `go run greet.go` (optionally pass `--port` to change the default) and make a sample request using [Restish](https://rest.sh/) (or `curl`):

```sh
# Get the message from the server
$ restish :8888/greeting/world
HTTP/1.1 200 OK
...
{
	$schema: "http://localhost:8888/schemas/GreetingOutputBody.json",
	message: "Hello, world!"
}
```

Even though the example is tiny you can also see some generated documentation at http://localhost:8888/docs. The generated OpenAPI is available at http://localhost:8888/openapi.json or http://localhost:8888/openapi.yaml.

Check out the [Huma tutorial](https://huma.rocks/tutorial/installation/) for a step-by-step guide to get started.

# Documentation

See the [https://huma.rocks/](https://huma.rocks/) website for full documentation in a presentation that's easier to navigate and search then this README. You can find the source for the site in the `docs` directory of this repo.

Official Go package documentation can always be found at https://pkg.go.dev/github.com/danielgtaylor/huma/v2.

# Articles & Mentions

- [APIs in Go with Huma 2.0](https://dgt.hashnode.dev/apis-in-go-with-huma-20)
- [Reducing Go Dependencies: A case study of dependency reduction in Huma](https://dgt.hashnode.dev/reducing-go-dependencies)
- [Golang News & Libs & Jobs shared on Twitter/X](https://twitter.com/golangch/status/1752175499701264532)
- Featured in Go Weekly [#495](https://golangweekly.com/issues/495) & [#498](https://golangweekly.com/issues/498)
- [Bump.sh Deploying Docs from Huma](https://docs.bump.sh/guides/bump-sh-tutorials/huma/)
- Mentioned in [Composable HTTP Handlers Using Generics](https://www.willem.dev/articles/generic-http-handlers/)

# Who is using Huma?

Huma is used by many companies and open-source projects. See the [Who is using Huma?](https://huma.rocks/why/#who-is-using-huma) page for a list!

Be sure to star the project if you find it useful!

<a href="https://star-history.com/#danielgtaylor/huma&Date">
	
		
		
		
	
</a>

---

## File: docs/docs/features/api-docs.md

---
---

# Generated API Documentation

## Generated API Docs { .hidden }

Huma uses the OpenAPI spec to generate interactive API documentation using third-party tools. By default, [Stoplight Elements](https://stoplight.io/open-source/elements) is used to render the documentation at the API's `config.DocsPath` which defaults to `/docs`.

You can switch to other documentation renderers using `config.DocsRenderer`. The following renderers are supported out of the box:

- `huma.DocsRendererStoplightElements` (default)
- `huma.DocsRendererScalar`
- `huma.DocsRendererSwaggerUI`



!!! info "Disabling the Docs"

    You can disable the built-in documentation by setting `config.DocsPath` to an empty string, then register your own route on the underlying router. The `DocsRenderer*` functions in [`api.go`](https://github.com/danielgtaylor/huma/blob/main/api.go) show what to return.

!!! warning "Middleware Conflicts"

    Some middleware can interfere with the documentation renderer's ability to fetch the OpenAPI spec. For example, [go-chi/chi](https://github.com/go-chi/chi)'s `middleware.URLFormat` will rewrite URLs that end in `.json` or `.yaml` (e.g. `/openapi.json` -> `/openapi`), which can lead to 404 errors for the spec. If you encounter this, consider disabling that middleware or configuring it to skip the OpenAPI and documentation paths.

## Customizing Documentation

Each renderer accepts its own options through `config.DocsRendererConfig`. Set it to any value that marshals to JSON (a `map[string]any` is easiest), and Huma writes it into the docs HTML. Scalar and SwaggerUI support it; Stoplight Elements ignores it.

### Scalar Docs

[Scalar Docs](https://github.com/scalar/scalar#readme) provide a featureful and customizable API documentation experience that feels similar to Postman in your browser.

```go title="code.go"
router := chi.NewRouter()
config := huma.DefaultConfig("Docs Example", "1.0.0")
config.DocsRenderer = huma.DocsRendererScalar

// Optional. Scalar reads these from the `data-configuration` attribute. See
// https://github.com/scalar/scalar/blob/main/documentation/configuration.md
config.DocsRendererConfig = map[string]any{
	"theme":      "mars", // one of: default, alternate, moon, purple, solarized, ...
	"hideModels": true,   // hide the models section
}

api := humachi.New(router, config)
```



### Stoplight Elements

[Stoplight Elements](https://stoplight.io/open-source/elements) is the default renderer, so you get it without setting `config.DocsRenderer` at all. It doesn't read `config.DocsRendererConfig`.

```go title="code.go"
router := chi.NewRouter()
config := huma.DefaultConfig("Docs Example", "1.0.0")

api := humachi.New(router, config)
```



### SwaggerUI

[SwaggerUI](https://github.com/swagger-api/swagger-ui#readme) is an older but proven documentation generator that is widely used in the industry. It provides a more traditional API documentation experience.

```go title="code.go"
router := chi.NewRouter()
config := huma.DefaultConfig("Docs Example", "1.0.0")
config.DocsRenderer = huma.DocsRendererSwaggerUI

// Optional. These fields are merged into the SwaggerUIBundle config object. See
// https://swagger.io/docs/open-source-tools/swagger-ui/usage/configuration/
config.DocsRendererConfig = map[string]any{
	"defaultModelsExpandDepth": -1,   // hide the models section
	"tryItOutEnabled":          true, // enable "Try it out" by default
	"persistAuthorization":     true, // keep auth across page reloads
}

api := humachi.New(router, config)
```



## Dive Deeper

-   Reference
    -   [`huma.Config`](https://pkg.go.dev/github.com/danielgtaylor/huma/v2#Config) the API config
    -   [`huma.DefaultConfig`](https://pkg.go.dev/github.com/danielgtaylor/huma/v2#DefaultConfig) the default API config

---

## File: docs/docs/features/auto-patch.md

---
---

# Auto Patch

## Auto Patch { .hidden }

If a `GET` and a `PUT` exist for the same resource, but no `PATCH` exists at server start up, then a `PATCH` operation can be generated for you to make editing more convenient for clients. You can opt-in to this behavior with the `autopatch` package:

```go
import "github.com/danielgtaylor/huma/v2/autopatch"

// ...

// Later in the code *after* registering operations...
autopatch.AutoPatch(api)
```

If the `GET` returns an `ETag` or `Last-Modified` header, then these will be used to make conditional requests on the `PUT` operation to prevent distributed write conflicts that might otherwise overwrite someone else's changes.

The following formats are supported out of the box, selected via the `Content-Type` header:

-   [JSON Merge Patch](https://datatracker.ietf.org/doc/html/rfc7386) `application/merge-patch+json`
-   [Shorthand Merge Patch](https://rest.sh/docs/reference/shorthand/) `application/merge-patch+shorthand`
-   [JSON Patch](https://www.rfc-editor.org/rfc/rfc6902.html) `application/json-patch+json`

!!! info "Merge on Steroids"

    You can think of the Shorthand Merge Patch as an extension to the JSON merge patch with support for field paths, arrays, and a few other features. Patches like this are possible, appending an item to an array (creating it if needed):

    ```yaml
    {
    	foo.bar[]: "baz",
    }
    ```

If the `PATCH` request has no `Content-Type` header, or uses `application/json` or a variant thereof, then JSON Merge Patch is assumed.

## Disabling Auto Patch

The auto patch feature can be disabled per resource by setting metadata on an operation:

```go title="code.go" hl_lines="7-9"
// Register an operation that won't get a PATCH generated.
huma.Register(api, huma.Operation{
	OperationID: "get-greeting",
	Method:      http.MethodGet,
	Path:        "/greeting/{name}",
	Summary:     "Get a greeting",
	Metadata: map[string]interface{}{
		"autopatch": false,
	},
}, func(ctx context.Context, input *GreetingInput) (*GreetingOutput, error) {
	// ...
})
```

## Dive Deeper

-   Reference
    -   [`autopatch`](https://pkg.go.dev/github.com/danielgtaylor/huma/v2/autopatch) package
-   External Links
    -   [HTTP PATCH Method](https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/PATCH)
    -   [RFC7386 JSON Merge Patch](https://datatracker.ietf.org/doc/html/rfc7386)
    -   [Shorthand Merge Patch](https://rest.sh/docs/reference/shorthand/)
    -   [RFC6902 JSON Patch](https://www.rfc-editor.org/rfc/rfc6902.html)

---

## File: docs/docs/features/bring-your-own-router.md

---
---

# BYOR (Bring Your Own Router)

## BYOR (Bring Your Own Router) { .hidden }

Huma is designed to be router-agnostic to enable incremental adoption in existing and new services across a large number of organizations. This means you can use any router you want, or even write your own. The only requirement is an implementation of a small [`huma.Adapter`](https://pkg.go.dev/github.com/danielgtaylor/huma/v2#Adapter) interface. This is how Huma integrates with your router.

Adapters are in the [`adapters`](https://github.com/danielgtaylor/huma/tree/main/adapters) directory and named after the router they support. Many common routers are supported out of the box (in alphabetical order):

-   [BunRouter](https://bunrouter.uptrace.dev/) via [`humabunrouter`](https://pkg.go.dev/github.com/danielgtaylor/huma/v2/adapters/humabunrouter)
-   [chi](https://github.com/go-chi/chi) via [`humachi`](https://pkg.go.dev/github.com/danielgtaylor/huma/v2/adapters/humachi)
-   [Echo](https://echo.labstack.com/) via [`humaecho`](https://pkg.go.dev/github.com/danielgtaylor/huma/v2/adapters/humaecho)
-   [Fiber](https://gofiber.io/) via [`humafiber`](https://pkg.go.dev/github.com/danielgtaylor/huma/v2/adapters/humafiber)
-   [gin](https://gin-gonic.com/) via [`humagin`](https://pkg.go.dev/github.com/danielgtaylor/huma/v2/adapters/humagin)
-   [Go 1.22+ `http.ServeMux`](https://pkg.go.dev/net/http@master#ServeMux) via [`humago`](https://pkg.go.dev/github.com/danielgtaylor/huma/v2/adapters/humago) (requires `go 1.22` or newer in `go.mod`)
-   [gorilla/mux](https://github.com/gorilla/mux) via [`humamux`](https://pkg.go.dev/github.com/danielgtaylor/huma/v2/adapters/humamux)
-   [httprouter](https://github.com/julienschmidt/httprouter) via [`humahttprouter`](https://pkg.go.dev/github.com/danielgtaylor/huma/v2/adapters/humahttprouter)

!!! info "New Adapters"

    Writing your own adapter is quick and simple, and PRs are accepted for additional adapters to be built-in.

## Chi Example

Adapters are instantiated by wrapping your router and providing a Huma configuration object which describes the API. Here is a simple example using Chi:

```go title="main.go"
import (
	"github.com/danielgtaylor/huma/v2"
	"github.com/danielgtaylor/huma/v2/adapters/humachi"
	"github.com/go-chi/chi/v5"
)

// Create your router.
router := chi.NewMux()

// Wrap the router with Huma to create an API instance.
api := humachi.New(router, huma.DefaultConfig("My API", "1.0.0"))

// Register your operations with the API.
// ...

// Start the server!
http.ListenAndServe(":8888", r)
```

For existing services using Chi v4, you can use `humachi.NewV4` instead.

## Route Groups & Base URLs

Many routers support grouping of operations under a common base URL path. This is useful for versioning APIs or grouping related operations together. Huma's router adapters can be instantiated using these route groups. You can set the `OpenAPI().Servers` slice to include the base URL path for the group, enabling the correct URLs to be generated for the docs & schemas. Here is an example:

```go title="main.go"
mux := chi.NewMux()
mux.Route("/api", func(r chi.Router) {
	config := huma.DefaultConfig("My API", "1.0.0")
	config.Servers = []*huma.Server{
		{URL: "https://example.com/api"},
	}
	api = humachi.New(r, config)

	// Register operations...
	huma.Get(api, "/demo", func(ctx context.Context, input *struct{}) (*struct{}, error) {
		// TODO: Implement me!
		return nil, nil
	})
})
http.ListenAndServe("localhost:8888", mux)
```

The OpenAPI, docs, schemas, etc will all be generated with the `/api` prefix.

```sh title="Shell"
# Call the demo operation
restish :8888/api/demo

# Get the OpenAPI
restish :8888/api/openapi.yaml
```

The following scenarios are supported:

| Server Base URL | Route Group | Register Path | Client Request & Description                                                                                                                        |
| --------------- | ----------- | ------------- | --------------------------------------------------------------------------------------------------------------------------------------------------- |
| -               | -           | `/api/demo`   | `GET /api/demo`  The default simple case.                                                                                                      |
| `/api`          | -           | `/demo`       | `GET /api/demo` &rarr; `GET /demo`  E.g. an API gateway which forwards requests to the service after stripping the `/api` prefix off the path. |
| `/api`          | `/api`      | `/demo`       | `GET /api/demo`  Unmodified request with route groups.                                                                                         |

## Dive Deeper

The adapter converts a router-specific request context like `http.Request` or `fiber.Ctx` into the router-agnostic `huma.Context`, which is then used to call your operation's handler function.

```mermaid
graph LR
	Request([Request])
	OperationHandler[Operation Handler]

	Request --> Router
	Router -->|http.Requestfiber.Ctxetc| huma.Adapter
	subgraph huma.API
		huma.Adapter -->|huma.Context| OperationHandler
	end
```

-   Features
    -   [Registering operations](./operations.md)
-   Reference
    -   [`huma.Context`](https://pkg.go.dev/github.com/danielgtaylor/huma/v2#Context) a router-agnostic request/response context
    -   [`huma.Adapter`](https://pkg.go.dev/github.com/danielgtaylor/huma/v2#Adapter) the router-agnostic adapter interface
    -   [`huma.API`](https://pkg.go.dev/github.com/danielgtaylor/huma/v2#API) the API instance
    -   [`huma.NewAPI`](https://pkg.go.dev/github.com/danielgtaylor/huma/v2#NewAPI) creates an API instance (called by adapters)
    -   [`huma.Register`](https://pkg.go.dev/github.com/danielgtaylor/huma/v2#Register) registers new operations
    -   [`huma.OpenAPI`](https://pkg.go.dev/github.com/danielgtaylor/huma/v2#OpenAPI) configures things like the server URLs & base path

---

## File: docs/docs/features/cli.md

---
---

# Service CLI

## Service CLI { .hidden }

Huma ships with a built-in lightweight utility to wrap your service with a CLI, enabling you to run it with different arguments and easily write custom commands to do things like print out the OpenAPI or run on-demand database migrations.

The CLI options use a similar strategy to input & output structs, enabling you to use the same pattern for validation and documentation of command line arguments. It uses [Cobra](https://cobra.dev/) under the hood, enabling custom commands and including automatic environment variable binding and more.

```go title="main.go"
// 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"`
}

func main() {
	// Then, create the CLI.
	cli := humacli.New(func(hooks humacli.Hooks, opts *Options) {
		fmt.Printf("I was run with debug:%v host:%v port%v\n",
			opts.Debug, opts.Host, opts.Port)
	})

	// Run the thing!
	cli.Run()
}
```

You can then run the CLI and see the results:

```sh title="Terminal"
// Run with defaults
$ go run main.go
I was run with debug:false host: port:8888

// Run with options
$ go run main.go --debug=true --host=localhost --port=8000
I was run with debug:true host:localhost port:8000
```

To do useful work, you will want to register a handler for the default start command and optionally a way to gracefully shutdown the server:

```go title="main.go"
cli := humacli.New(func(hooks humacli.Hooks, opts *Options) {
	// Set up the router and API
	// ...

	// Create the HTTP server.
	server := http.Server{
		Addr:    fmt.Sprintf(":%d", options.Port),
		Handler: router,
	}

	hooks.OnStart(func() {
		// Start your server here
		server.ListenAndServe()
	})

	hooks.OnStop(func() {
		// Gracefully shutdown your server here
		ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
		defer cancel()
		server.Shutdown(ctx)
	})
})
```

!!! info "Naming"

    Option fields are automatically converted to `--kebab-casing` for use on the command line. If you want to use a different name, use the `name` struct tag to override the default behavior!

## Passing Options

Options can be passed explicitly as command-line arguments to the service or they can be provided by environment variables prefixed with `SERVICE_`. For example, to run the service on port 8000:

```bash
# Example passing command-line args
$ go run main.go --port=8000

# Short arguments are also supported
$ go run main.go -p 8000

# Example passing by environment variables
$ SERVICE_PORT=8000 go run main.go
```

!!! warning "Precedence"

    If both environment variable and command-line arguments are present, then command-line arguments take priority.

## Custom Options

Custom options are defined by adding to your options struct. The following types are supported:

| Type            | Example Inputs                    |
| --------------- | --------------------------------- |
| `bool`          | `true`, `false`                   |
| `int` / `int64` | `1234`, `5`, `-1`                 |
| `string`        | `prod`, `http://api.example.tld/` |
| `time.Duration` | `500ms`, `3s`, `1h30m`            |

The following struct tags are available:

| Tag       | Description                             | Example                 |
| --------- | --------------------------------------- | ----------------------- |
| `default` | Default value (parsed automatically)    | `default:"123"`         |
| `doc`     | Describe the option                     | `doc:"Who to greet"`    |
| `name`    | Override the name of the option         | `name:"my-option-name"` |
| `short`   | Single letter short name for the option | `short:"p"` for `-p`    |

Here is an example of how to use them:

```go title="main.go"
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"`
}
```

## Custom Commands

You can access the root [`cobra.Command`](https://pkg.go.dev/github.com/spf13/cobra#Command) via `cli.Root()` and add new custom commands via `cli.Root().AddCommand(...)`. For example, to have a command print out the generated OpenAPI:

```go title="main.go"
var api huma.API

// ... set up the CLI, create the API wrapping the router ...

cli.Root().AddCommand(&cobra.Command{
	Use:   "openapi",
	Short: "Print the OpenAPI spec",
	Run: func(cmd *cobra.Command, args []string) {
		b, err := api.OpenAPI().YAML()
		if err != nil {
			panic(err)
		}
		fmt.Println(string(b))
	},
})
```

!!! info "Note"

    You can use `api.OpenAPI().DowngradeYAML()` to output OpenAPI 3.0 instead of 3.1 for tools that don't support 3.1 yet.

Now you can run your service and use the new command: `go run . openapi`. Notice that it never starts the server; it just runs your command handler code. Some ideas for custom commands:

-   Print the OpenAPI spec
-   Print JSON Schemas
-   Run database migrations
-   Run customer scenario tests
-   Bundle common actions into a single utility command, like adding a new user

### Custom Commands with Options

If you want to access your custom options struct with custom commands, use the [`huma.WithOptions(func(cmd *cobra.Command, args []string, options *YourOptions)) func(cmd *cobra.Command, args []string)`](https://pkg.go.dev/github.com/danielgtaylor/huma/v2#WithOptions) utility function. It ensures the options are parsed and available before running your command.

!!! info "More Customization"

    You can also overwrite `cli.Root().Run` to completely customize how you run the server. Or just ditch the `cli` package altogether!

## App Name & Version

You can set the app name and version to be used in the help output and version command. By default, the app name is the name of the binary and the version is unset. You can set them using the root [`cobra.Command`](https://pkg.go.dev/github.com/spf13/cobra#Command)'s `Use` and `Version` fields:

```go title="main.go"
// cli := humacli.New(...)

cmd := cli.Root()
cmd.Use = "appname"
cmd.Version = "1.0.1"

cli.Run()
```

Then you will see something like this:

```sh title="Terminal"
$ go run ./demo --help
Usage:
  appname [flags]

Flags:
  -h, --help            help for appname
  -p, --port int         (default 8888)
  -v, --version         version for appname

$ go run ./demo --version
appname version 1.0.1
```

## Dive Deeper

-   Tutorial
    -   [Service Configuration Tutorial](../tutorial/service-configuration.md) includes a working CLI example
-   How-To
    -   [Graceful Shutdown](../how-to/graceful-shutdown.md) on service stop
-   Reference
    -   [`humacli.CLI`](https://pkg.go.dev/github.com/danielgtaylor/huma/v2/humacli#CLI) the CLI instance
    -   [`humacli.New`](https://pkg.go.dev/github.com/danielgtaylor/huma/v2/humacli#New) creates a new CLI instance
    -   [`humacli.Hooks`](https://pkg.go.dev/github.com/danielgtaylor/huma/v2/humacli#Hooks) for startup / shutdown
    -   [`humacli.WithOptions`](https://pkg.go.dev/github.com/danielgtaylor/huma/v2/humacli#WithOptions) wraps a command with options parsing
    -   [`huma.API`](https://pkg.go.dev/github.com/danielgtaylor/huma/v2#API) the API instance
-   External Links
    -   [Cobra](https://cobra.dev/) CLI library

---

## File: docs/docs/features/cli-auto-config.md

---
---

# CLI AutoConfig

Huma includes built-in support for an OpenAPI 3 extension that enables CLI auto-configuration. This allows tools like [Restish](https://rest.sh/) to automatically configure themselves to talk to your API with the correct endpoints, authentication mechanism, etc without the user needing to know anything about your API.

```go
o := api.OpenAPI()
o.Components.SecuritySchemes["my-scheme"] = &huma.SecurityScheme{
	Type: "oauth2",
	// ... security scheme definition ...
}
o.Extensions["x-cli-config"] = huma.AutoConfig{
	Security: "my-scheme",
	Params: map[string]string{
		"client_id": "abc123",
		"authorize_url": "https://example.tld/authorize",
		"token_url": "https://example.tld/token",
		"scopes": "read,write",
	}
}
```

See the [CLI AutoConfiguration](https://rest.sh/docs/reference/openapi/) documentation for more info, including how to ask the user for custom parameters.

---

## File: docs/docs/features/conditional-requests.md

---
---

# Conditional Requests

## Conditional Requests { .hidden }

There are built-in utilities for handling [conditional requests](https://developer.mozilla.org/en-US/docs/Web/HTTP/Conditional_requests), which serve two broad purposes:

1. Sparing bandwidth on reading a document that has not changed, i.e. "only send if the version is different from what I already have".
2. Preventing multiple writers from clobbering each other's changes, i.e. "only save if the version on the server matches what I saw last".

Adding support for handling conditional requests requires four steps:

1. Import the [`github.com/danielgtaylor/huma/v2/conditional`](https://pkg.go.dev/github.com/danielgtaylor/huma/v2/conditional) package.
2. (optional) Add the response definition (`304 Not Modified` for reads or `412 Precondition Failed` for writes)
3. Add `conditional.Params` to your input struct.
4. Check if conditional params were passed and handle them. The `HasConditionalParams()` and `PreconditionFailed(...)` methods can help with this.

## Example

Implementing a conditional read might look like:

```go
huma.Register(api, huma.Operation{
	OperationID: "get-resource",
	Method:      http.MethodGet,
	Path:        "/resource",
	Summary:     "Get a resource",
}, func(ctx context.Context, input struct {
	conditional.Params
}) (*YourOutput, error) {
	if input.HasConditionalParams() {
		// TODO: Get the ETag and last modified time from the resource.
		etag := ""
		modified := time.Time{}

		// If preconditions fail, abort the request processing. Response status
		// codes are already set for you, but you can optionally provide a body.
		// Returns an HTTP 304 not modified.
		if err := input.PreconditionFailed(etag, modified); err != nil {
			return err
		}

		// Otherwise do the normal request processing here...
		// ...
	}
})
```

!!! info "Conditional Request Efficiency"

    Note that it is more efficient to construct custom DB queries to handle conditional requests, however Huma is not aware of your database. The built-in conditional utilities are designed to be generic and work with any data source, and are a quick and easy way to get started with conditional request handling.

## Dive Deeper

-   Reference
    -   [`conditional`](https://pkg.go.dev/github.com/danielgtaylor/huma/v2/conditional) package
    -   [`conditional.Params`](https://pkg.go.dev/github.com/danielgtaylor/huma/v2/conditional/Params)
-   External Links
    -   [Conditional Requests](https://developer.mozilla.org/en-US/docs/Web/HTTP/Conditional_requests)

---

## File: docs/docs/features/groups.md

---
---

# Groups

## Groups { .hidden }

Operations can be grouped under common route prefixes and share middleware, operation modifier functions, and response transformers. This is done using the `huma.Group` wrapper around a `huma.API` instance, which can then be passed to `huma.Register` and its convenience wrappers like `huma.Get`, `huma.Post`, etc.

```go
grp := huma.NewGroup(api, "/v1")
grp.UseMiddleware(authMiddleware)

huma.Get(grp, "/users", func(ctx context.Context, input *struct{}) (*UsersResponse, error) {
	// ...
})
```

The above example will register a `GET /v1/users` operation with the `authMiddleware` running before the operation handler.

!!! info "Groups & Documentation"

    Groups assume that `huma.Register` or one of its convenience wrappers is used to register operations. If you are not, then you may need to invoke `group.DocumentOperation(*huma.Operation)` to ensure that the operation is documented correctly.

## Group Features

Groups support the following features:

-   One or more path prefixes for all operations in the group.
-   Middleware that runs before each operation in the group.
-   Operation modifiers that run at operation registration time.
-   Response transformers that run after each operation in the group.

## Prefixes

Groups can have one or more path prefixes that are prepended to all operations in the group. This is useful for grouping related operations under a common prefix and is typically done with a single prefix.

```go
grp := huma.NewGroup(api, "/prefix1", "/prefix2", "...")
```

This is just a convenience for the following equivalent code:

```go
grp := huma.NewGroup(api)
grp.UseModifier(huma.PrefixModifier("/prefix1", "/prefix2", "..."))
```

The built-in [`huma.PrefixModifier`](https://pkg.go.dev/github.com/danielgtaylor/huma/v2#PrefixModifier) will adjust the operation's ID and tags when more than one prefix is used. If you wish to customize this behavior, you can write your own operation modifier.

## Middleware

Middleware functions are run before each operation handler in the group. They can be used for common tasks like authentication, logging, and error handling. Middleware functions are registered using the `UseMiddleware` method on a group.

```go
grp.UseMiddleware(func(ctx huma.Context, next func(huma.Context)) {
	// Do something before the operation runs
	next(ctx)
})
```

## Operation Modifiers

Operation modifiers are functions that run at operation registration time. They can be used to modify the operation before it is registered. Operation modifiers are registered using the `UseModifier` method on a group.

```go
grp.UseModifier(func(op *huma.Operation, next func(*huma.Operation)) {
	op.Summary = "A summary for all operations in this group"
	op.Tags = []string{"my-tag"}
    next(op)
})
```

There is also a simplified form you can use:

```go
grp.UseSimpleModifier(func(op *huma.Operation) {
	op.Summary = "A summary for all operations in this group"
	op.Tags = []string{"my-tag"}
})
```

## Response Transformers

Response transformers are functions that run after each operation handler in the group. They can be used to modify the response before it is returned to the client. Response transformers are registered using the `UseResponseTransformer` method on a group.

```go
grp.UseTransformer(func(ctx huma.Context, status string, v any) (any, error) {
	// Do something with the output
	return output, nil
})
```

## Customizing Documentation

Groups implement [`huma.OperationDocumenter`](https://pkg.go.dev/github.com/danielgtaylor/huma/v2#OperationDocumenter) which bypasses the normal flow of documentation generation and instead calls a function. This allows you to customize the documentation for all operations in the group. You can override the `DocumentOperation` method to customize the documentation if needed:

```go
type MyGroup huma.Group

func (g *MyGroup) DocumentOperation(op *huma.Operation) {
	g.ModifyOperation(op, func(op *huma.Operation) {
		if documenter, ok := g.API.(huma.OperationDocumenter); ok {
			// Support nested operation documenters (i.e. groups of groups).
			documenter.DocumentOperation(op)
		} else {
			// Default behavior to add operations.
			if op.Hidden {
				return
			}
			g.OpenAPI().AddOperation(op)
		}
	})
}
```

## Dive Deeper

-   Features
    -   [Operations](./operations.md) registration & workflows
    -   [Middleware](./middleware.md) for operations
    -   [Response Transformers](./response-transformers.md) to modify response bodies
-   Reference
    -   [`huma.Register`](https://pkg.go.dev/github.com/danielgtaylor/huma/v2#Register) register an operation
    -   [`huma.Middlewares`](https://pkg.go.dev/github.com/danielgtaylor/huma/v2#Middlewares) list of middleware
    -   [`huma.Transformer`](https://pkg.go.dev/github.com/danielgtaylor/huma/v2#Transformer) response transformers
    -   [`huma.OperationDocumenter`](https://pkg.go.dev/github.com/danielgtaylor/huma/v2#OperationDocumenter) to customize OpenAPI generation
    -   [`huma.API`](https://pkg.go.dev/github.com/danielgtaylor/huma/v2#API) the API instance

---

## File: docs/docs/features/index.md

---
---

# Features

Huma is a modern, simple, fast & flexible micro framework for building HTTP REST/RPC APIs in Golang backed by OpenAPI 3 and JSON Schema. Pronounced IPA: [/'hjuːmɑ/](https://en.wiktionary.org/wiki/Wiktionary:International_Phonetic_Alphabet). The goals of this project are to provide:

-   A modern REST or HTTP RPC API backend framework for Go developers
    -   Described by [OpenAPI 3.1](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.1.0.md) & [JSON Schema](https://json-schema.org/)
-   Incremental adoption for teams with existing services
    -   Bring your own router, middleware, and logging/metrics
    -   Extensible OpenAPI & JSON Schema layer to document existing routes
-   Guard rails to prevent common mistakes
-   Documentation that can't get out of date
-   High-quality generated developer tooling

Features include:

-   Declarative interface on top of your router of choice:
    -   Operation & model documentation
    -   Request params (path, query, or header)
    -   Request body
    -   Responses (including errors)
    -   Response headers
-   JSON Errors using [RFC9457](https://tools.ietf.org/html/rfc9457) and `application/problem+json` by default (but can be changed)
-   Per-operation request size limits with sane defaults
-   [Content negotiation](https://developer.mozilla.org/en-US/docs/Web/HTTP/Content_negotiation) between server and client
    -   Support for JSON ([RFC 8259](https://tools.ietf.org/html/rfc8259)) and optional CBOR ([RFC 7049](https://tools.ietf.org/html/rfc7049)) content types via the `Accept` header with the default config.
-   Conditional requests support, e.g. `If-Match` or `If-Unmodified-Since` header utilities.
-   Optional automatic generation of `PATCH` operations that support:
    -   [RFC 7386](https://www.rfc-editor.org/rfc/rfc7386) JSON Merge Patch
    -   [RFC 6902](https://www.rfc-editor.org/rfc/rfc6902) JSON Patch
    -   [Shorthand](https://github.com/danielgtaylor/shorthand) patches
-   Annotated Go types for input and output models
    -   Generates JSON Schema from Go types
    -   Static typing for path/query/header params, bodies, response headers, etc.
    -   Automatic input model validation & error handling
-   Documentation generation using [Stoplight Elements](https://stoplight.io/open-source/elements)
-   Optional CLI built-in, configured via arguments or environment variables
    -   Set via e.g. `-p 8000`, `--port=8000`, or `SERVICE_PORT=8000`
    -   Startup actions & graceful shutdown built-in
-   Generates OpenAPI for access to a rich ecosystem of tools
    -   Mocks with [API Sprout](https://github.com/danielgtaylor/apisprout) or [Prism](https://stoplight.io/open-source/prism)
    -   SDKs with [OpenAPI Generator](https://github.com/OpenAPITools/openapi-generator) or [oapi-codegen](https://github.com/deepmap/oapi-codegen)
    -   CLI with [Restish](https://rest.sh/)
    -   And [plenty](https://openapi.tools/) [more](https://apis.guru/awesome-openapi3/category.html)
-   Generates JSON Schema for each resource using optional `describedby` link relation headers as well as optional `$schema` properties in returned objects that integrate into editors for validation & completion.

!!! info "Mascot"

    Hi there! I'm the happy Huma whale here to provide help. You'll see me leave helpful tips throughout the docs.

Official Go package documentation can always be found at [https://pkg.go.dev/github.com/danielgtaylor/huma/v2](https://pkg.go.dev/github.com/danielgtaylor/huma/v2). Read on for an introduction to the various features available in Huma.

---

## File: docs/docs/features/json-schema-registry.md

---
---

## JSON Schema

Using the default Huma config (or manually via the [`huma.SchemaLinkTransformer`](https://pkg.go.dev/github.com/danielgtaylor/huma/v2#SchemaLinkTransformer)), each resource operation returns a `describedby` HTTP link relation header which references a JSON-Schema file. These schemas use the [`config.SchemasPath`](https://pkg.go.dev/github.com/danielgtaylor/huma/v2#Config) to serve their content. For example:

```http title="HTTP Response"
Link: </schemas/Note.json>; rel="describedby"
```

Object resources (i.e. not arrays or simple scalars) can also optionally return a `$schema` property with such a link, which enables the described-by relationship to outlive the HTTP request (i.e. saving the body to a file for later editing) and enables some editors like [VSCode](https://code.visualstudio.com/docs/languages/json#_mapping-in-the-json) to provide code completion and validation as you type.

```json title="response.json"
{
	"$schema": "http://localhost:8888/schemas/Note.json",
	"title": "I am a note title",
	"contents": "Example note contents",
	"labels": ["todo"]
}
```

Operations which accept objects as input will ignore the `$schema` property, so it is safe to submit back to the API, aka "round-trip" the data.

### Disabling `$schema`

If you want to disable the `$schema` property and the `Link` header in responses, you can set the `CreateHooks` to `nil` in your configuration before creating the API. This prevents the default `SchemaLinkTransformer` from being registered.

```go
config := huma.DefaultConfig("My API", "1.0.0")
config.CreateHooks = nil

// Create the API using the config...
```

Alternatively, you can manually manage your `Transformers` and `OnAddOperation` hooks in a custom configuration if you only want to disable one of them.

!!! info "Editing"

    The `$schema` field is incredibly powerful when paired with Restish's [edit](https://rest.sh/docs/reference/edit-command/) command, giving you a quick and easy way to edit strongly-typed resources in your favorite editor.

## Schema Registry

Huma uses a customizable registry to keep track of all the schemas that have been generated from Go structs. This is used to avoid generating the same schema multiple times, and to provide a way to reference schemas by name for OpenAPI operations & hosted JSON Schemas.

The default schema implementation uses a `map` to store schemas by name,generated from the Go type name without the package name. This supports recursive schemas and generates simple names like `Thing` or `ThingList`.

!!! warning "Schema Names"

    Note that by design the default registry does **not** support multiple models with the same name in different packages. For example, adding both `foo.Thing` and `bar.Thing` will result in a conflict. You can work around this by defining a new type like `type BarThing bar.Thing` and using that instead, or using a custom [registry naming function](https://pkg.go.dev/github.com/danielgtaylor/huma/v2#DefaultSchemaNamer).

### Custom Registry

You can create your own registry with custom behavior by implementing the [`huma.Registry`](https://pkg.go.dev/github.com/danielgtaylor/huma/v2#Registry) interface and setting it on `config.OpenAPI.Components.Schemas` when creating your API.

## Dive Deeper

-   Reference
    -   [`huma.Schema`](https://pkg.go.dev/github.com/danielgtaylor/huma/v2#Schema) is a JSON Schema
    -   [`huma.Registry`](https://pkg.go.dev/github.com/danielgtaylor/huma/v2#Registry) generates & stores JSON Schemas
    -   [`huma.DefaultSchemaNamer`](https://pkg.go.dev/github.com/danielgtaylor/huma/v2#DefaultSchemaNamer) names schemas from types
    -   [`huma.Config`](https://pkg.go.dev/github.com/danielgtaylor/huma/v2#Config) the API config
    -   [`huma.DefaultConfig`](https://pkg.go.dev/github.com/danielgtaylor/huma/v2#DefaultConfig) the default API config
    -   [`huma.OpenAPI`](https://pkg.go.dev/github.com/danielgtaylor/huma/v2#OpenAPI) the OpenAPI spec
    -   [`huma.Components`](https://pkg.go.dev/github.com/danielgtaylor/huma/v2#Components) contains the `Schemas` registry
-   External Links
    -   [JSON Schema spec](https://json-schema.org/)
    -   [OpenAPI 3.1 Components Object](https://spec.openapis.org/oas/v3.1.0#components-object)
-   See Also
    -   [Model Validation](./model-validation.md) utility to validate custom JSON objects