or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

core-configuration.mddata-filtering.mderror-handling.mdindex.mdrecord-modes.mdrequest-matching.mdrequest-response.mdserialization.mdtest-integration.md

request-response.mddocs/

0

# Request and Response Processing

1

2

HTTP request and response representation with case-insensitive headers, body processing, and URI parsing capabilities. VCR.py provides internal models for capturing and manipulating HTTP interactions.

3

4

## Capabilities

5

6

### Request Class

7

8

VCR's representation of an HTTP request with automatic body and header processing.

9

10

```python { .api }

11

class Request:

12

"""

13

VCR's representation of an HTTP request.

14

15

Args:

16

method (str): HTTP method (GET, POST, etc.)

17

uri (str): Full request URI

18

body: Request body (str, bytes, file-like object, or iterable)

19

headers: Request headers (dict or HeadersDict)

20

"""

21

def __init__(self, method: str, uri: str, body, headers): ...

22

```

23

24

### Request Properties

25

26

Properties providing parsed access to request components.

27

28

```python { .api }

29

@property

30

def headers(self) -> HeadersDict:

31

"""Case-insensitive dictionary of request headers."""

32

33

@property

34

def body(self):

35

"""

36

Request body, returned in appropriate format:

37

- File-like objects: Returns BytesIO

38

- Iterables: Returns iterator

39

- Other types: Returns as-is

40

"""

41

42

@property

43

def method(self) -> str:

44

"""HTTP method (GET, POST, PUT, DELETE, etc.)"""

45

46

@property

47

def uri(self) -> str:

48

"""Complete request URI"""

49

50

@property

51

def scheme(self) -> str:

52

"""URI scheme (http, https)"""

53

54

@property

55

def host(self) -> str:

56

"""Request host/domain"""

57

58

@property

59

def port(self) -> int:

60

"""Request port number"""

61

62

@property

63

def path(self) -> str:

64

"""URI path component"""

65

66

@property

67

def query(self) -> str:

68

"""Query string component"""

69

```

70

71

### HeadersDict Class

72

73

Case-insensitive dictionary implementation for HTTP headers.

74

75

```python { .api }

76

class HeadersDict(dict):

77

"""

78

Case-insensitive dictionary for HTTP headers.

79

80

Allows access to headers regardless of case:

81

headers['Content-Type'] == headers['content-type']

82

"""

83

def __init__(self, data=None): ...

84

```

85

86

## Usage Examples

87

88

### Creating Requests

89

90

```python

91

from vcr.request import Request, HeadersDict

92

93

# Basic request creation

94

request = Request(

95

method='GET',

96

uri='https://api.example.com/users?page=1',

97

body=None,

98

headers={'User-Agent': 'MyApp/1.0', 'Accept': 'application/json'}

99

)

100

101

# POST request with body

102

post_request = Request(

103

method='POST',

104

uri='https://api.example.com/users',

105

body='{"name": "John", "email": "john@example.com"}',

106

headers={

107

'Content-Type': 'application/json',

108

'Authorization': 'Bearer token123'

109

}

110

)

111

```

112

113

### Accessing Request Properties

114

115

```python

116

# URI components

117

print(request.scheme) # 'https'

118

print(request.host) # 'api.example.com'

119

print(request.port) # 443 (default for https)

120

print(request.path) # '/users'

121

print(request.query) # 'page=1'

122

123

# Headers (case-insensitive access)

124

print(request.headers['User-Agent']) # 'MyApp/1.0'

125

print(request.headers['user-agent']) # 'MyApp/1.0' (same value)

126

print(request.headers.get('Accept')) # 'application/json'

127

```

128

129

### Body Processing

130

131

```python

132

import io

133

134

# String body

135

request = Request(

136

method='POST',

137

uri='https://api.example.com/data',

138

body='{"key": "value"}',

139

headers={}

140

)

141

print(request.body) # '{"key": "value"}'

142

143

# File-like body

144

file_obj = io.BytesIO(b'file content')

145

request = Request(

146

method='PUT',

147

uri='https://api.example.com/upload',

148

body=file_obj,

149

headers={}

150

)

151

# Request automatically reads and stores file content

152

# request.body returns BytesIO with the content

153

154

# Iterable body

155

request = Request(

156

method='POST',

157

uri='https://api.example.com/stream',

158

body=[b'chunk1', b'chunk2', b'chunk3'],

159

headers={}

160

)

161

# Request converts iterable to list

162

# request.body returns iterator over the chunks

163

```

164

165

### HeadersDict Usage

166

167

```python

168

from vcr.request import HeadersDict

169

170

# Create headers dict

171

headers = HeadersDict({

172

'Content-Type': 'application/json',

173

'Authorization': 'Bearer token123',

174

'X-Custom-Header': 'custom-value'

175

})

176

177

# Case-insensitive access

178

print(headers['content-type']) # 'application/json'

179

print(headers['AUTHORIZATION']) # 'Bearer token123'

180

print(headers['x-custom-header']) # 'custom-value'

181

182

# Standard dict operations work

183

headers['New-Header'] = 'new-value'

184

del headers['X-Custom-Header']

185

186

# Iteration preserves original case

187

for key, value in headers.items():

188

print(f"{key}: {value}")

189

```

190

191

### Request Modification

192

193

```python

194

# Modifying request components

195

request = Request('GET', 'https://api.example.com/data', None, {})

196

197

# Update headers (creates new HeadersDict if needed)

198

request.headers['Authorization'] = 'Bearer new-token'

199

request.headers['Accept'] = 'application/xml'

200

201

# Body modification

202

request.body = '{"updated": "data"}'

203

204

# Note: URI components are read-only properties

205

# To change URI, create a new Request object

206

```

207

208

### Integration with VCR Filters

209

210

```python

211

def sanitize_request(request):

212

"""Example filter function that modifies requests before recording"""

213

# Remove sensitive headers

214

if 'authorization' in request.headers:

215

request.headers['authorization'] = 'REDACTED'

216

217

# Modify query parameters by reconstructing URI

218

if 'api_key' in request.uri:

219

# Custom logic to remove api_key from URI

220

pass

221

222

return request

223

224

# Use with VCR configuration

225

my_vcr = vcr.VCR(before_record_request=sanitize_request)

226

```

227

228

## Advanced Usage

229

230

### Custom Header Processing

231

232

```python

233

from vcr.request import HeadersDict

234

235

def normalize_headers(headers_dict):

236

"""Normalize header values for consistent recording"""

237

normalized = HeadersDict()

238

239

for key, value in headers_dict.items():

240

if key.lower() == 'user-agent':

241

# Normalize user agent strings

242

normalized[key] = 'Normalized-User-Agent/1.0'

243

elif key.lower() == 'date':

244

# Remove timestamp headers for deterministic recording

245

continue

246

else:

247

normalized[key] = value

248

249

return normalized

250

251

# Apply to requests during processing

252

request.headers = normalize_headers(request.headers)

253

```

254

255

### Body Content Analysis

256

257

```python

258

import json

259

from urllib.parse import parse_qs

260

261

def analyze_request_body(request):

262

"""Analyze and potentially modify request body"""

263

if request.headers.get('content-type', '').startswith('application/json'):

264

try:

265

# Parse and potentially modify JSON body

266

data = json.loads(request.body)

267

# Remove sensitive fields

268

data.pop('password', None)

269

data.pop('api_secret', None)

270

request.body = json.dumps(data)

271

except (json.JSONDecodeError, TypeError):

272

pass

273

274

elif request.headers.get('content-type') == 'application/x-www-form-urlencoded':

275

# Handle form data

276

try:

277

data = parse_qs(request.body)

278

# Process form fields

279

if 'password' in data:

280

data['password'] = ['REDACTED']

281

request.body = '&'.join(f"{k}={v[0]}" for k, v in data.items())

282

except (ValueError, TypeError):

283

pass

284

285

return request

286

```