or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

brokers.mddecorators.mddiscovery.mdhttp.mdindex.mdrequests.mdrouters.mdscheduling.mdspecs.mdsystem-utils.md

requests.mddocs/

0

# Request and Response Handling

1

2

Core request/response abstractions used across all transport types. Provides unified interfaces for handling different types of requests with content, parameters, and user context.

3

4

## Capabilities

5

6

### Core Request Interface

7

8

Abstract base class providing unified request handling across all transport types.

9

10

```python { .api }

11

class Request:

12

user: Optional[UUID]

13

has_content: bool

14

has_params: bool

15

async def content(self, **kwargs) -> Any: ...

16

async def params(self, **kwargs) -> dict[str, Any]: ...

17

async def _content(self, **kwargs) -> Any: ... # Abstract

18

async def _params(self, **kwargs) -> dict[str, Any]: ... # Abstract

19

def __eq__(self, other: Any) -> bool: ... # Abstract

20

def __repr__(self) -> str: ... # Abstract

21

```

22

23

### Core Response Interface

24

25

Concrete response class for returning data with status codes.

26

27

```python { .api }

28

class Response:

29

def __init__(self, data: Any = None, *, status: int = 200): ...

30

has_content: bool

31

status: int

32

async def content(self, **kwargs) -> Any: ...

33

def __eq__(self, other: Any) -> bool: ...

34

def __repr__(self) -> str: ...

35

def __hash__(self) -> int: ...

36

37

class ResponseException:

38

def __init__(self, *args, status: int = 400): ...

39

status: int

40

```

41

42

**Usage Examples:**

43

44

```python

45

from minos.networks import Response, ResponseException

46

47

# Create successful response

48

response = Response({"user_id": "123", "name": "John"})

49

print(response.status) # 200

50

51

# Create response with custom status

52

created_response = Response({"id": "123"}, status=201)

53

54

# Check if response has content

55

if response.has_content:

56

data = await response.content()

57

58

# Raise response exception

59

if not valid_data:

60

raise ResponseException("Invalid data", status=400)

61

```

62

63

### In-Memory Request Implementation

64

65

Concrete request implementation for testing and in-memory usage.

66

67

```python { .api }

68

class InMemoryRequest(Request):

69

def __init__(self, content: Any = None, params: dict[str, Any] = None, user: Optional[UUID] = None): ...

70

user: Optional[UUID]

71

has_content: bool

72

has_params: bool

73

async def _content(self, **kwargs) -> Any: ...

74

async def _params(self, **kwargs) -> dict[str, Any]: ...

75

def __eq__(self, other: Any) -> bool: ...

76

def __repr__(self) -> str: ...

77

```

78

79

**Usage Examples:**

80

81

```python

82

from minos.networks import InMemoryRequest

83

from uuid import UUID

84

85

# Create request with content

86

request = InMemoryRequest(

87

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

88

params={"user_id": "123"},

89

user=UUID("12345678-1234-5678-9012-123456789012")

90

)

91

92

# Access request data

93

if request.has_content:

94

content = await request.content()

95

print(content["name"]) # "John"

96

97

if request.has_params:

98

params = await request.params()

99

print(params["user_id"]) # "123"

100

101

print(request.user) # UUID object

102

```

103

104

### Wrapped Request Implementation

105

106

Request wrapper that applies transformations to content and parameters.

107

108

```python { .api }

109

from typing import Callable, Union, Awaitable

110

111

ContentAction = Callable[[Any, ...], Union[Any, Awaitable[Any]]]

112

ParamsAction = Callable[[dict[str, Any], ...], Union[dict[str, Any], Awaitable[dict[str, Any]]]]

113

114

class WrappedRequest(Request):

115

def __init__(self, base: Request, content_action: Optional[ContentAction] = None, params_action: Optional[ParamsAction] = None): ...

116

user: Optional[UUID]

117

has_content: bool

118

has_params: bool

119

async def _content(self, **kwargs) -> Any: ...

120

async def _params(self, **kwargs) -> dict[str, Any]: ...

121

def __eq__(self, other: Any) -> bool: ...

122

def __repr__(self) -> str: ...

123

```

124

125

**Usage Examples:**

126

127

```python

128

from minos.networks import WrappedRequest, InMemoryRequest

129

130

# Base request

131

base_request = InMemoryRequest(content={"name": "john"})

132

133

# Transform content to uppercase

134

def uppercase_name(content):

135

if isinstance(content, dict) and "name" in content:

136

content["name"] = content["name"].upper()

137

return content

138

139

# Create wrapped request with transformation

140

wrapped_request = WrappedRequest(

141

base=base_request,

142

content_action=uppercase_name

143

)

144

145

# Content is transformed when accessed

146

content = await wrapped_request.content()

147

print(content["name"]) # "JOHN"

148

149

# Async transformation example

150

async def async_transform(content):

151

# Simulate async processing

152

await asyncio.sleep(0.1)

153

content["processed"] = True

154

return content

155

156

wrapped_async = WrappedRequest(

157

base=base_request,

158

content_action=async_transform

159

)

160

```

161

162

### Context Variables

163

164

Context variables for passing request metadata across async boundaries.

165

166

```python { .api }

167

from contextvars import ContextVar

168

from uuid import UUID

169

170

REQUEST_USER_CONTEXT_VAR: ContextVar[Optional[UUID]]

171

```

172

173

**Usage Examples:**

174

175

```python

176

from minos.networks import REQUEST_USER_CONTEXT_VAR

177

from uuid import UUID

178

179

# Set user context

180

user_id = UUID("12345678-1234-5678-9012-123456789012")

181

REQUEST_USER_CONTEXT_VAR.set(user_id)

182

183

# Access user context in handlers

184

def get_current_user() -> Optional[UUID]:

185

return REQUEST_USER_CONTEXT_VAR.get(None)

186

187

@enroute.broker.command("user.update")

188

async def update_user(request: Request) -> Response:

189

current_user = get_current_user()

190

if current_user:

191

print(f"User {current_user} is making the request")

192

193

# Process update

194

return Response({"updated": True})

195

```

196

197

## Advanced Usage

198

199

### Custom Request Implementation

200

201

```python

202

class DatabaseRequest(Request):

203

def __init__(self, query_id: str, db_connection):

204

self.query_id = query_id

205

self.db_connection = db_connection

206

self._user = None

207

208

@property

209

def user(self) -> Optional[UUID]:

210

return self._user

211

212

@property

213

def has_content(self) -> bool:

214

return True

215

216

@property

217

def has_params(self) -> bool:

218

return True

219

220

async def _content(self, **kwargs) -> Any:

221

# Fetch content from database

222

result = await self.db_connection.fetch_one(

223

"SELECT content FROM requests WHERE id = ?",

224

(self.query_id,)

225

)

226

return result["content"] if result else None

227

228

async def _params(self, **kwargs) -> dict[str, Any]:

229

# Fetch params from database

230

result = await self.db_connection.fetch_one(

231

"SELECT params FROM requests WHERE id = ?",

232

(self.query_id,)

233

)

234

return result["params"] if result else {}

235

236

def __eq__(self, other):

237

return isinstance(other, DatabaseRequest) and other.query_id == self.query_id

238

239

def __repr__(self):

240

return f"DatabaseRequest(query_id={self.query_id})"

241

```

242

243

### Request/Response Middleware Patterns

244

245

```python

246

class LoggingRequest(WrappedRequest):

247

def __init__(self, base: Request):

248

async def log_content(content):

249

print(f"Accessing content: {type(content)}")

250

return content

251

252

async def log_params(params):

253

print(f"Accessing params: {list(params.keys())}")

254

return params

255

256

super().__init__(

257

base=base,

258

content_action=log_content,

259

params_action=log_params

260

)

261

262

class ValidatedRequest(WrappedRequest):

263

def __init__(self, base: Request, schema: dict):

264

self.schema = schema

265

266

async def validate_content(content):

267

# Validate content against schema

268

if not self._validate(content, self.schema):

269

raise ValueError("Content validation failed")

270

return content

271

272

super().__init__(base=base, content_action=validate_content)

273

274

def _validate(self, data, schema):

275

# Implement validation logic

276

return True

277

278

# Usage in handlers

279

@enroute.broker.command("user.create")

280

async def create_user(request: Request) -> Response:

281

# Wrap request with validation

282

schema = {"type": "object", "required": ["email", "name"]}

283

validated_request = ValidatedRequest(request, schema)

284

285

try:

286

user_data = await validated_request.content()

287

# Process creation

288

return Response({"created": True})

289

except ValueError as e:

290

return Response({"error": str(e)}, status=400)

291

```

292

293

### Response Builders and Factories

294

295

```python

296

class ResponseBuilder:

297

def __init__(self):

298

self._data = None

299

self._status = 200

300

self._headers = {}

301

302

def with_data(self, data: Any):

303

self._data = data

304

return self

305

306

def with_status(self, status: int):

307

self._status = status

308

return self

309

310

def with_header(self, key: str, value: str):

311

self._headers[key] = value

312

return self

313

314

def build(self) -> Response:

315

response = Response(self._data, status=self._status)

316

# Custom response with headers would need HttpResponse

317

return response

318

319

# Factory methods for common responses

320

class ResponseFactory:

321

@staticmethod

322

def success(data: Any = None) -> Response:

323

return Response(data, status=200)

324

325

@staticmethod

326

def created(data: Any = None) -> Response:

327

return Response(data, status=201)

328

329

@staticmethod

330

def not_found(message: str = "Not found") -> Response:

331

return Response({"error": message}, status=404)

332

333

@staticmethod

334

def bad_request(message: str = "Bad request") -> Response:

335

return Response({"error": message}, status=400)

336

337

# Usage

338

@enroute.rest.command("/users", method="POST")

339

async def create_user(request: Request) -> Response:

340

try:

341

user_data = await request.content()

342

new_user = create_user_logic(user_data)

343

return ResponseFactory.created(new_user)

344

except ValueError:

345

return ResponseFactory.bad_request("Invalid user data")

346

```

347

348

### Request Processing Pipelines

349

350

```python

351

class RequestPipeline:

352

def __init__(self):

353

self.middlewares = []

354

355

def add_middleware(self, middleware_func):

356

self.middlewares.append(middleware_func)

357

return self

358

359

async def process(self, request: Request) -> Request:

360

current_request = request

361

for middleware in self.middlewares:

362

current_request = await middleware(current_request)

363

return current_request

364

365

# Middleware functions

366

async def auth_middleware(request: Request) -> Request:

367

# Add user authentication

368

if hasattr(request, 'headers'):

369

auth_header = request.headers.get("Authorization")

370

if auth_header:

371

user = authenticate_user(auth_header)

372

REQUEST_USER_CONTEXT_VAR.set(user)

373

return request

374

375

async def logging_middleware(request: Request) -> Request:

376

print(f"Processing request: {type(request)}")

377

return LoggingRequest(request)

378

379

# Usage in handlers

380

pipeline = RequestPipeline()

381

pipeline.add_middleware(auth_middleware)

382

pipeline.add_middleware(logging_middleware)

383

384

@enroute.broker.command("user.update")

385

async def update_user(request: Request) -> Response:

386

# Process request through pipeline

387

processed_request = await pipeline.process(request)

388

389

# Handle the processed request

390

user_data = await processed_request.content()

391

return Response({"updated": True})

392

```