How to parse and build headers¶
There are three ways to get a header instance. This guide shows when to use each.
Parse a raw value string¶
Header.parse(value) is the only string entry point. It validates against the header’s abnf
grammar and raises ValueError on bad input.
from http_fields import CacheControl
cc = CacheControl.parse("max-age=3600, no-cache, immutable")
cc.max_age # 3600
cc.no_cache # True
cc.immutable # True
Pass the header value only — not the Name: value line.
Construct from parsed fields¶
parse() is the entry point for strings. Direct construction takes each field as its
already-parsed type — a leaf type or value object — so a constructor never re-runs the grammar
on untrusted text. Passing a raw string where a typed field is expected raises TypeError
pointing you back to parse().
Plain scalars still coerce their natural Python value:
from datetime import datetime, timezone
from http_fields import Age, Date, RetryAfter
Age(60) # int -> NonNegativeInt
Date(datetime(2030, 1, 1, tzinfo=timezone.utc)) # a datetime
RetryAfter(120) # delay-seconds ...
RetryAfter(datetime(2030, 1, 1, tzinfo=timezone.utc)) # ... or an HTTP-date
List-style headers take their leaf types as varargs. Build the leaves (each validates itself),
or parse() a whole value string:
from http_fields import Connection, FieldName, Token, Vary
Connection(Token("keep-alive"), Token("close"))
Vary(FieldName("accept-encoding"), FieldName("accept-language"))
Connection.parse("keep-alive, close") # from a raw string
Connection("keep-alive") — a bare string — is now a TypeError; use Connection.parse(...).
Headers with structured values take value objects, which coerce their string parts to validated leaves:
from http_fields import Protocol, Upgrade
Upgrade(Protocol("HTTP", "2"), Protocol("WebSocket"))
Upgrade.parse("HTTP/2, WebSocket") # equivalent, from a string
Use a builder classmethod¶
Headers whose piece-wise construction is richer than their stored fields expose a builder:
Header |
Builder |
|---|---|
|
|
|
|
|
|
|
|
from http_fields import ContentType, SetCookie, ETag
ContentType.of(type="text", subtype="html", charset="utf-8")
SetCookie.build(cookie_name="SID", cookie_value="abc", path="/", secure=True)
ETag.from_tag("deadbeef", weak=True)
.build() validates its input strictly (raising TypeError/ValueError); SetCookie.parse()
uses the more lenient RFC 6265 §5 algorithm for interoperability.
Wildcard headers¶
If-Match / If-None-Match use wildcard=True for *; AltSvc uses clear=True for clear:
from http_fields import IfMatch, AltSvc
from http_fields.visitors.rfc9110 import EntityTag
IfMatch(wildcard=True) # "*"
IfMatch(EntityTag("deadbeef")) # a specific tag
AltSvc(clear=True) # "clear"
Serialize¶
Any header round-trips to text and bytes:
str(cc) # 'Cache-Control: max-age=3600,no-cache,immutable'
cc.value # 'max-age=3600,no-cache,immutable'
bytes(cc) # b'Cache-Control: ...'
cc.asgi_value # (b'Cache-Control', b'...')