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

http.mddocs/

0

# HTTP Services

1

2

HTTP server functionality with REST support, request/response abstractions, routing, and connector patterns. Provides the foundation for building HTTP APIs and web services with the Minos framework.

3

4

## Capabilities

5

6

### HTTP Port and Service Management

7

8

Port classes for managing HTTP service lifecycle with automatic setup and teardown.

9

10

```python { .api }

11

class HttpPort:

12

connector: HttpConnector

13

@staticmethod

14

def _get_connector(connector: Optional[HttpConnector] = None, http_connector: Optional[HttpConnector] = None, **kwargs) -> HttpConnector: ...

15

async def _start(self) -> None: ...

16

async def _stop(self, err: Exception = None) -> None: ...

17

18

class RestService:

19

"""Deprecated - use HttpPort instead"""

20

```

21

22

**Usage Examples:**

23

24

```python

25

from minos.networks import HttpPort

26

from minos.common import Config

27

28

# Create HTTP port from configuration

29

config = Config("config.yml")

30

http_port = HttpPort._from_config(config)

31

32

# Start the HTTP server

33

await http_port.start()

34

35

# Server runs and handles requests...

36

37

# Stop the HTTP server

38

await http_port.stop()

39

```

40

41

### HTTP Adapters

42

43

Adapters that manage HTTP routers and provide route aggregation.

44

45

```python { .api }

46

class HttpAdapter:

47

def __init__(self, routers: list[HttpRouter]): ...

48

routes: dict[HttpEnrouteDecorator, Callable]

49

routers: list[HttpRouter]

50

@classmethod

51

def _from_config(cls, config: Config, **kwargs) -> HttpAdapter: ...

52

@staticmethod

53

def _routers_from_config(config: Config, **kwargs) -> list[HttpRouter]: ...

54

```

55

56

**Usage Examples:**

57

58

```python

59

from minos.networks import HttpAdapter, RestHttpRouter

60

61

# Create routers

62

router = RestHttpRouter._from_config(config)

63

64

# Create adapter with routers

65

adapter = HttpAdapter(routers=[router])

66

67

# Access aggregated routes

68

routes = adapter.routes

69

for decorator, callback in routes.items():

70

print(f"Route: {decorator.path} {decorator.method}")

71

```

72

73

### HTTP Connectors

74

75

Abstract base classes for HTTP server implementations that bridge framework-specific HTTP servers with Minos request/response system.

76

77

```python { .api }

78

from typing import TypeVar, Generic, Callable, Awaitable

79

80

RawRequest = TypeVar("RawRequest")

81

RawResponse = TypeVar("RawResponse")

82

83

class HttpConnector(Generic[RawRequest, RawResponse]):

84

def __init__(self, adapter: HttpAdapter, host: Optional[str] = None, port: Optional[int] = None, max_connections: int = 5): ...

85

host: str # default: "0.0.0.0"

86

port: int # default: 8080

87

routes: dict[HttpEnrouteDecorator, Callable]

88

adapter: HttpAdapter

89

@classmethod

90

def _from_config(cls, config: Config, **kwargs) -> HttpConnector: ...

91

async def start(self) -> None: ...

92

async def stop(self) -> None: ...

93

def mount_routes(self) -> None: ...

94

def mount_route(self, path: str, method: str, callback: Callable[[Request], Optional[Response]]) -> None: ...

95

def adapt_callback(self, callback: Callable[[Request], Union[Optional[Response], Awaitable[Optional[Response]]]]) -> Callable[[RawRequest], Awaitable[RawResponse]]: ...

96

97

# Abstract methods - implement in subclasses

98

async def _start(self) -> None: ...

99

async def _stop(self) -> None: ...

100

def _mount_route(self, path: str, method: str, adapted_callback: Callable) -> None: ...

101

async def _build_request(self, request: RawRequest) -> Request: ...

102

async def _build_response(self, response: Optional[Response]) -> RawResponse: ...

103

async def _build_error_response(self, message: str, status: int) -> RawResponse: ...

104

```

105

106

**Usage Examples:**

107

108

```python

109

# Custom connector implementation

110

class FastAPIConnector(HttpConnector[FastAPIRequest, FastAPIResponse]):

111

async def _start(self) -> None:

112

# Start FastAPI server

113

pass

114

115

async def _stop(self) -> None:

116

# Stop FastAPI server

117

pass

118

119

def _mount_route(self, path: str, method: str, adapted_callback: Callable) -> None:

120

# Mount route on FastAPI app

121

pass

122

123

async def _build_request(self, request: FastAPIRequest) -> Request:

124

# Convert FastAPI request to Minos Request

125

pass

126

127

async def _build_response(self, response: Optional[Response]) -> FastAPIResponse:

128

# Convert Minos Response to FastAPI response

129

pass

130

131

# Using the connector

132

connector = FastAPIConnector(adapter=adapter, host="localhost", port=8080)

133

await connector.start()

134

```

135

136

### HTTP Request Handling

137

138

HTTP-specific request classes with URL parameters, query parameters, and header support.

139

140

```python { .api }

141

class HttpRequest:

142

user: Optional[UUID]

143

headers: dict[str, str]

144

content_type: str

145

has_url_params: bool

146

has_query_params: bool

147

async def url_params(self, type_: Optional[Union[type, str]] = None, **kwargs) -> Any: ...

148

async def query_params(self, type_: Optional[Union[type, str]] = None, **kwargs) -> Any: ...

149

150

# Inherited from Request

151

has_content: bool

152

has_params: bool

153

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

154

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

155

```

156

157

**Usage Examples:**

158

159

```python

160

@enroute.rest.query("/users/{user_id}", method="GET")

161

async def get_user(request: HttpRequest) -> Response:

162

# Get URL parameters

163

url_params = await request.url_params()

164

user_id = url_params["user_id"]

165

166

# Get query parameters

167

query_params = await request.query_params()

168

include_posts = query_params.get("include_posts", False)

169

170

# Access headers

171

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

172

173

# Get request body (if any)

174

if request.has_content:

175

body = await request.content()

176

177

return Response({"user_id": user_id, "include_posts": include_posts})

178

179

@enroute.rest.command("/users/{user_id}", method="PUT")

180

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

181

# URL parameters from path

182

url_params = await request.url_params()

183

user_id = url_params["user_id"]

184

185

# Request body content

186

user_data = await request.content()

187

188

# Update user logic

189

updated_user = {"id": user_id, **user_data}

190

191

return Response(updated_user)

192

```

193

194

### HTTP Response Handling

195

196

HTTP-specific response classes with content type management and status codes.

197

198

```python { .api }

199

class HttpResponse:

200

def __init__(self, *args, content_type: str = "application/json", **kwargs): ...

201

content_type: str

202

status: int

203

has_content: bool

204

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

205

@classmethod

206

def from_response(cls, response: Optional[Response]) -> HttpResponse: ...

207

208

class HttpResponseException:

209

status: int # default: 400

210

```

211

212

**Usage Examples:**

213

214

```python

215

@enroute.rest.query("/users/{user_id}", method="GET")

216

async def get_user(request: HttpRequest) -> HttpResponse:

217

url_params = await request.url_params()

218

user_id = url_params["user_id"]

219

220

# Return JSON response (default)

221

return HttpResponse({"id": user_id, "name": "John Doe"})

222

223

@enroute.rest.query("/users/{user_id}/avatar", method="GET")

224

async def get_user_avatar(request: HttpRequest) -> HttpResponse:

225

# Return image response

226

avatar_data = get_avatar_bytes()

227

return HttpResponse(

228

avatar_data,

229

content_type="image/png",

230

status=200

231

)

232

233

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

234

async def create_user(request: HttpRequest) -> HttpResponse:

235

try:

236

user_data = await request.content()

237

if not user_data.get("email"):

238

raise HttpResponseException(status=400)

239

240

# Create user logic

241

new_user = {"id": "123", **user_data}

242

return HttpResponse(new_user, status=201)

243

244

except ValueError:

245

raise HttpResponseException(status=400)

246

```

247

248

### Router Integration

249

250

Integration with the routing system for HTTP request handling.

251

252

```python { .api }

253

class RestHttpRouter:

254

routes: dict[HttpEnrouteDecorator, Callable]

255

def _filter_routes(self, routes: dict[EnrouteDecorator, Callable]) -> dict[EnrouteDecorator, Callable]: ...

256

```

257

258

**Usage Examples:**

259

260

```python

261

from minos.networks import RestHttpRouter, enroute

262

263

class UserController:

264

@enroute.rest.query("/users", method="GET")

265

async def list_users(self, request: HttpRequest) -> HttpResponse:

266

return HttpResponse({"users": []})

267

268

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

269

async def create_user(self, request: HttpRequest) -> HttpResponse:

270

user_data = await request.content()

271

return HttpResponse({"id": "123", **user_data}, status=201)

272

273

# Create router and filter routes

274

config = Config("config.yml")

275

router = RestHttpRouter._from_config(config)

276

277

# Router automatically discovers and filters HTTP routes

278

http_routes = router.routes

279

```

280

281

## Advanced Usage

282

283

### Complete HTTP Service Setup

284

285

```python

286

from minos.networks import HttpPort, enroute, HttpRequest, HttpResponse

287

from minos.common import Config

288

289

class UserAPI:

290

@enroute.rest.query("/users", method="GET")

291

async def list_users(self, request: HttpRequest) -> HttpResponse:

292

query_params = await request.query_params()

293

page = query_params.get("page", 1)

294

limit = query_params.get("limit", 10)

295

296

# Fetch users with pagination

297

users = fetch_users(page=page, limit=limit)

298

return HttpResponse({"users": users, "page": page})

299

300

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

301

async def create_user(self, request: HttpRequest) -> HttpResponse:

302

user_data = await request.content()

303

304

# Validate required fields

305

if not user_data.get("email"):

306

return HttpResponse({"error": "Email required"}, status=400)

307

308

# Create user

309

new_user = create_user(user_data)

310

return HttpResponse(new_user, status=201)

311

312

@enroute.rest.query("/users/{user_id}", method="GET")

313

async def get_user(self, request: HttpRequest) -> HttpResponse:

314

url_params = await request.url_params()

315

user_id = url_params["user_id"]

316

317

user = get_user_by_id(user_id)

318

if not user:

319

return HttpResponse({"error": "User not found"}, status=404)

320

321

return HttpResponse(user)

322

323

@enroute.rest.command("/users/{user_id}", method="PUT")

324

async def update_user(self, request: HttpRequest) -> HttpResponse:

325

url_params = await request.url_params()

326

user_id = url_params["user_id"]

327

user_data = await request.content()

328

329

updated_user = update_user(user_id, user_data)

330

return HttpResponse(updated_user)

331

332

@enroute.rest.command("/users/{user_id}", method="DELETE")

333

async def delete_user(self, request: HttpRequest) -> HttpResponse:

334

url_params = await request.url_params()

335

user_id = url_params["user_id"]

336

337

delete_user(user_id)

338

return HttpResponse(status=204)

339

340

# Setup HTTP service

341

config = Config("config.yml")

342

http_port = HttpPort._from_config(config)

343

344

# Start HTTP server

345

await http_port.start()

346

print(f"HTTP server running on {http_port.connector.host}:{http_port.connector.port}")

347

348

# Server handles requests automatically based on decorators

349

# Stop when done

350

await http_port.stop()

351

```

352

353

### Custom Content Types and Response Handling

354

355

```python

356

@enroute.rest.query("/users/{user_id}/report", method="GET")

357

async def generate_user_report(request: HttpRequest) -> HttpResponse:

358

url_params = await request.url_params()

359

user_id = url_params["user_id"]

360

361

# Check accept header for response format

362

accept = request.headers.get("Accept", "application/json")

363

364

user_data = get_user_data(user_id)

365

366

if "application/pdf" in accept:

367

pdf_data = generate_pdf_report(user_data)

368

return HttpResponse(

369

pdf_data,

370

content_type="application/pdf",

371

status=200

372

)

373

elif "text/csv" in accept:

374

csv_data = generate_csv_report(user_data)

375

return HttpResponse(

376

csv_data,

377

content_type="text/csv",

378

status=200

379

)

380

else:

381

# Default JSON response

382

return HttpResponse(user_data)

383

```

384

385

### Error Handling and Middleware

386

387

```python

388

from minos.networks import HttpResponseException

389

390

@enroute.rest.command("/users/{user_id}/validate", method="POST")

391

async def validate_user(request: HttpRequest) -> HttpResponse:

392

try:

393

# Check authentication

394

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

395

if not auth_header:

396

raise HttpResponseException(status=401)

397

398

# Get and validate input

399

url_params = await request.url_params()

400

user_id = url_params["user_id"]

401

validation_data = await request.content()

402

403

if not validation_data:

404

raise HttpResponseException(status=400)

405

406

# Perform validation

407

result = validate_user_data(user_id, validation_data)

408

return HttpResponse({"valid": result})

409

410

except ValueError as e:

411

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

412

except PermissionError:

413

return HttpResponse({"error": "Forbidden"}, status=403)

414

except Exception as e:

415

return HttpResponse({"error": "Internal server error"}, status=500)

416

```