Skip to content


When handler functions return Go objects, they will be serialized to bytes for transmission back to the client.

Default Formats#

The config.Formats maps either a content type name or extension (suffix) to a huma.Format instance.

The default configuration for Huma includes support for JSON (RFC 8259) and optionally CBOR (RFC 7049) content types via the Accept header. This is done by registering the following content types using huma.DefaultJSONFormat:

  • application/json
  • Anything ending with +json

CBOR support can be enabled by importing the cbor package, which adds cbor.DefaultCBORFormat to the default list of formats:

import (

    _ ""

This adds the following content types:

  • application/cbor
  • Anything ending with +cbor

Other Formats

You can easily add support for additional serialization formats, including binary formats like Protobuf if desired.

Custom Formats#

Huma supports custom serialization formats by implementing the huma.Format interface. Serialization formats are set on the API configuration at API creation time and selected by client-driven content negotiation.

Writing a new format can be very simple, by just providing a marshal and unmarshal function:

var DefaultJSONFormat = Format{
	Marshal: func(w io.Writer, v any) error {
		return json.NewEncoder(w).Encode(v)
	Unmarshal: json.Unmarshal,

Content Negotiation#

Content negotiation allows clients to select the content type they are most comfortable working with when talking to the API. For request bodies, this uses the Content-Type header. For response bodies, it uses the Accept header. If none are present then JSON is usually selected as the default / preferred content type.

# Send YAML as input using Restish
$ echo 'foo: bar' | \
	restish put -H 'Content-Type:application/yaml'

# Get CBOR output from an API
$ restish -H 'Accept:application/cbor'
HTTP/2.0 200 OK
Content-Length: 318
Content-Type: application/cbor
Etag: O7fTqWETqWI

See the negotiation package for more info.

Dive Deeper#