Getting started

This tutorial walks you through the core of http-fields: parsing a header, reading its structured fields, building one from scratch, and turning it back into bytes. By the end you’ll understand the shape shared by every header in the library.

Install

uv add http-fields
# or: pip install http-fields

1. Parse a header

Every known header has a .parse() classmethod that takes the raw header value (not the whole Name: value line) and returns a validated instance:

from http_fields import ContentType

ct = ContentType.parse("text/html; charset=UTF-8")

The pieces are now structured attributes:

ct.type       # 'text'
ct.subtype    # 'html'
ct.charset    # 'UTF-8'   (compares case-insensitively)

Invalid input raises ValueError:

ContentType.parse("not-a-media-type")   # ValueError: Invalid ContentType value "..."

2. Serialize it back

str(header) gives the full field line; bytes(header) encodes it; .value is just the value part; .asgi_value is a (name, value) pair of ASCII bytes ready for an ASGI send dict:

str(ct)          # 'Content-Type: text/html;charset=UTF-8'
ct.value         # 'text/html;charset=UTF-8'
bytes(ct)        # b'Content-Type: text/html;charset=UTF-8'
ct.asgi_value    # (b'Content-Type', b'text/html;charset=UTF-8')

3. Build one from pieces

You don’t have to start from a string. Simple headers take their field directly; richer ones provide a builder classmethod (here, ContentType.of(...)):

from http_fields import Age, ContentType

Age(60)                                              # a scalar header takes its value
ContentType.of(type="text", subtype="html", charset="utf-8")

Both paths validate, so you can’t build a malformed header:

Age(-1)   # ValueError: Value must be non-negative.

4. Dispatch by name

If you have a header name and value (say, from an incoming request) and don’t know the type up front, Header.create() returns the right subclass — or a CustomHeader for an unrecognized name:

from http_fields import Header

Header.create("content-type", "text/plain")   # -> ContentType(...)
Header.create("x-request-id", "abc123")        # -> CustomHeader(...)

5. Headers are values

Every header is a frozen dataclass: immutable, comparable, and hashable.

from http_fields import Age

Age(1) == Age(1)          # True
len({Age(1), Age(1)})     # 1  (deduplicates)
Age(1).seconds = 2        # dataclasses.FrozenInstanceError

Where to go next