Skip to content

Commit f6b1844

Browse files
committed
Add doc for headers and trailers
1 parent 330263d commit f6b1844

File tree

1 file changed

+102
-0
lines changed

1 file changed

+102
-0
lines changed

docs/headers-and-trailers.md

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
# Headers & trailers
2+
3+
To integrate with other systems, you may need to read or write custom HTTP headers with your RPCs.
4+
For example, distributed tracing, authentication, authorization, and rate limiting often require
5+
working with headers. Connect also supports trailers, which serve a similar purpose but can be written
6+
after the response body. This document outlines how to work with headers and trailers.
7+
8+
## Headers
9+
10+
Connect headers are just HTTP headers - because Python's standard library does not provide a
11+
corresponding type, we provide `request.Headers`. For most use cases, it is equivalent to a
12+
dictionary while also providing additional methods to access multiple values for the same header
13+
key when needed. Clients always accept a normal dictionary as well when accepting headers.
14+
15+
In services, headers are available on the `RequestContext`:
16+
17+
=== "ASGI"
18+
19+
```python
20+
class GreetService:
21+
async def greet(self, request, ctx):
22+
print(ctx.request_headers().get("acme-tenant-id"))
23+
ctx.response_headers()["greet-version"] = "v1"
24+
return GreetResponse()
25+
```
26+
27+
=== "WSGI"
28+
29+
```python
30+
class GreetService:
31+
def greet(self, request, ctx):
32+
print(ctx.request_headers().get("acme-tenant-id"))
33+
ctx.response_headers()["greet-version"] = "v1"
34+
return GreetResponse()
35+
```
36+
37+
For clients, we find that it is not common to read headers, but is fully supported.
38+
To preserve client methods having simple signatures accepting and providing RPC
39+
messages, headers are accessible through a separate context manager, `client.ResponseMetadata`.
40+
41+
=== "Async"
42+
43+
```python
44+
from connectrpc.client import ResponseMetadata
45+
46+
client = GreetServiceClient("https://api.acme.com")
47+
with ResponseMetadata() as meta:
48+
res = await client.greet(GreetRequest(), headers={"acme-tenant-id": "1234"})
49+
print(meta.headers().get("greet-version"))
50+
```
51+
52+
=== "Sync"
53+
54+
```python
55+
from connectrpc.client import ResponseMetadata
56+
57+
client = GreetServiceClientSync("https://api.acme.com")
58+
with ResponseMetadata() as meta:
59+
res = client.greet(GreetRequest(), headers={"acme-tenant-id": "1234"})
60+
print(meta.headers().get("greet-version"))
61+
```
62+
63+
Supported protocols require that header keys contain only ASCII letters, numbers, underscores, hyphens, and
64+
periods, and the protocols reserve all keys beginning with "Connect-" or "Grpc-". Similarly, header values may
65+
contain only printable ASCII and spaces. In our experience, application code writing reserved or non-ASCII headers
66+
is unusual; rather than wrapping `request.Headers` in a fat validation layer, we rely on your good judgment.
67+
68+
## Trailers
69+
70+
Connect's APIs for manipulating response trailers work identically to headers. Trailers are most useful in
71+
streaming handlers, which may need to send some metadata to the client after sending a few messages.
72+
Unary handlers should nearly always use headers instead.
73+
74+
If you find yourself needing trailers, handlers and clients can access them much like headers:
75+
76+
=== "Async"
77+
78+
```python
79+
class GreetService:
80+
async def greet(self, request, ctx):
81+
ctx.response_trailers()["greet-version"] = "v1"
82+
return GreetResponse()
83+
84+
client = GreetServiceClient("https://api.acme.com")
85+
with ResponseMetadata() as meta:
86+
res = await client.greet(GreetRequest(), headers={"acme-tenant-id": "1234"})
87+
print(meta.trailers().get("greet-version"))
88+
```
89+
90+
=== "Sync"
91+
92+
```python
93+
class GreetService:
94+
def greet(self, request, ctx):
95+
ctx.response_trailers()["greet-version"] = "v1"
96+
return GreetResponse()
97+
98+
client = GreetServiceClientSync("https://api.acme.com")
99+
with ResponseMetadata() as meta:
100+
res = client.greet(GreetRequest(), headers={"acme-tenant-id": "1234"})
101+
print(meta.trailers().get("greet-version"))
102+
```

0 commit comments

Comments
 (0)