or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

authentication.mdcore-app.mdexceptions.mdindex.mdmcp.mdopenapi.mdrequest-response.mdstatus-codes.mdtemplating.mdwebsocket.md

exceptions.mddocs/

0

# Exception Handling

1

2

Exception classes for handling HTTP and WebSocket errors with proper status codes and error messages.

3

4

## Capabilities

5

6

### HTTP Exceptions

7

8

HTTP exception class for handling web application errors with appropriate status codes.

9

10

```python { .api }

11

class HTTPException(Exception):

12

def __init__(self, status_code: int, detail: str | None = None) -> None:

13

"""

14

HTTP exception with status code and detail message.

15

16

Args:

17

status_code: HTTP status code (e.g., 404, 500)

18

detail: Optional error detail message (defaults to standard HTTP phrase)

19

"""

20

21

def __str__(self) -> str:

22

"""String representation of the exception."""

23

24

def __repr__(self) -> str:

25

"""Detailed string representation for debugging."""

26

```

27

28

### WebSocket Exceptions

29

30

WebSocket exception class for handling WebSocket connection errors.

31

32

```python { .api }

33

class WebSocketException(Exception):

34

def __init__(self, code: int, reason: str | None = None) -> None:

35

"""

36

WebSocket exception with close code and reason.

37

38

Args:

39

code: WebSocket close code (e.g., 1000, 1001, 1002)

40

reason: Optional close reason message

41

"""

42

43

def __str__(self) -> str:

44

"""String representation of the exception."""

45

46

def __repr__(self) -> str:

47

"""Detailed string representation for debugging."""

48

```

49

50

## Usage Examples

51

52

### HTTP Exception Handling

53

54

```python

55

from robyn import Robyn, status_codes

56

from robyn.exceptions import HTTPException

57

58

app = Robyn(__file__)

59

60

@app.get("/user/<user_id>")

61

def get_user(request):

62

user_id = request.path_params["user_id"]

63

64

# Validate user ID

65

if not user_id.isdigit():

66

raise HTTPException(

67

status_code=status_codes.HTTP_400_BAD_REQUEST,

68

detail="User ID must be a number"

69

)

70

71

user_id = int(user_id)

72

73

# Check if user exists (example)

74

if user_id < 1 or user_id > 1000:

75

raise HTTPException(

76

status_code=status_codes.HTTP_404_NOT_FOUND,

77

detail=f"User {user_id} not found"

78

)

79

80

# Simulate authorization check

81

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

82

if not auth_header:

83

raise HTTPException(

84

status_code=status_codes.HTTP_401_UNAUTHORIZED,

85

detail="Authentication required"

86

)

87

88

return {"user_id": user_id, "name": f"User {user_id}"}

89

90

@app.get("/admin/users")

91

def admin_users(request):

92

# Check admin permissions

93

user_role = request.headers.get("X-User-Role")

94

if user_role != "admin":

95

raise HTTPException(

96

status_code=status_codes.HTTP_403_FORBIDDEN,

97

detail="Admin access required"

98

)

99

100

return {"users": ["alice", "bob", "charlie"]}

101

102

app.start()

103

```

104

105

### Global Exception Handler

106

107

```python

108

from robyn import Robyn, Response, status_codes

109

from robyn.exceptions import HTTPException

110

111

app = Robyn(__file__)

112

113

@app.exception

114

def handle_exception(request, exception):

115

"""Global exception handler for all unhandled exceptions."""

116

if isinstance(exception, HTTPException):

117

return Response(

118

status_code=exception.status_code,

119

headers={"Content-Type": "application/json"},

120

description=f'{{"error": "{exception.detail}"}}'

121

)

122

else:

123

# Handle unexpected exceptions

124

return Response(

125

status_code=status_codes.HTTP_500_INTERNAL_SERVER_ERROR,

126

headers={"Content-Type": "application/json"},

127

description='{"error": "Internal server error"}'

128

)

129

130

@app.get("/error-demo/<error_type>")

131

def error_demo(request):

132

error_type = request.path_params["error_type"]

133

134

if error_type == "not_found":

135

raise HTTPException(404, "Resource not found")

136

elif error_type == "bad_request":

137

raise HTTPException(400, "Invalid request parameters")

138

elif error_type == "unauthorized":

139

raise HTTPException(401) # Uses default message

140

elif error_type == "server_error":

141

# This will trigger the generic exception handler

142

raise ValueError("Something went wrong")

143

144

return {"message": "No error triggered"}

145

146

app.start()

147

```

148

149

### WebSocket Exception Handling

150

151

```python

152

from robyn import Robyn

153

from robyn.ws import WebSocket

154

from robyn.exceptions import WebSocketException

155

156

app = Robyn(__file__)

157

websocket = WebSocket(app, "/ws")

158

159

@websocket.on("connect")

160

def on_connect(websocket_connector):

161

# Validate connection (example)

162

auth_token = websocket_connector.query_params.get("token")

163

if not auth_token:

164

raise WebSocketException(

165

code=1008, # Policy violation

166

reason="Authentication token required"

167

)

168

169

print(f"Client {websocket_connector.id} connected")

170

171

@websocket.on("message")

172

def on_message(websocket_connector, message):

173

try:

174

# Process message

175

if message == "close":

176

raise WebSocketException(

177

code=1000, # Normal closure

178

reason="Client requested close"

179

)

180

181

# Echo message back

182

websocket_connector.sync_send_to(websocket_connector.id, f"Echo: {message}")

183

184

except Exception as e:

185

# Handle processing errors

186

raise WebSocketException(

187

code=1011, # Unexpected condition

188

reason=f"Message processing error: {str(e)}"

189

)

190

191

@websocket.on("close")

192

def on_close(websocket_connector):

193

print(f"Client {websocket_connector.id} disconnected")

194

195

app.add_web_socket("/ws", websocket)

196

app.start()

197

```

198

199

### Custom Exception Classes

200

201

```python

202

from robyn import Robyn, status_codes

203

from robyn.exceptions import HTTPException

204

205

# Custom business logic exceptions

206

class UserNotFoundError(HTTPException):

207

def __init__(self, user_id: int):

208

super().__init__(

209

status_code=status_codes.HTTP_404_NOT_FOUND,

210

detail=f"User with ID {user_id} not found"

211

)

212

213

class InsufficientPermissionsError(HTTPException):

214

def __init__(self, required_role: str):

215

super().__init__(

216

status_code=status_codes.HTTP_403_FORBIDDEN,

217

detail=f"Requires {required_role} role"

218

)

219

220

class ValidationError(HTTPException):

221

def __init__(self, field: str, message: str):

222

super().__init__(

223

status_code=status_codes.HTTP_422_UNPROCESSABLE_ENTITY,

224

detail=f"Validation error in {field}: {message}"

225

)

226

227

app = Robyn(__file__)

228

229

@app.post("/users")

230

def create_user(request):

231

user_data = request.json()

232

233

# Validation

234

if not user_data.get("email"):

235

raise ValidationError("email", "Email is required")

236

237

if "@" not in user_data["email"]:

238

raise ValidationError("email", "Invalid email format")

239

240

# Create user logic here

241

return {"message": "User created", "id": 123}

242

243

@app.get("/user/<user_id>/profile")

244

def get_user_profile(request):

245

user_id = int(request.path_params["user_id"])

246

247

# Check if user exists

248

if user_id > 1000: # Example check

249

raise UserNotFoundError(user_id)

250

251

# Check permissions

252

user_role = request.headers.get("X-User-Role")

253

if user_role not in ["admin", "user"]:

254

raise InsufficientPermissionsError("user")

255

256

return {"user_id": user_id, "profile": "User profile data"}

257

258

app.start()

259

```

260

261

### Exception Logging and Monitoring

262

263

```python

264

import logging

265

from robyn import Robyn, Response, status_codes

266

from robyn.exceptions import HTTPException, WebSocketException

267

268

# Configure logging

269

logging.basicConfig(level=logging.INFO)

270

logger = logging.getLogger(__name__)

271

272

app = Robyn(__file__)

273

274

@app.exception

275

def log_and_handle_exception(request, exception):

276

"""Exception handler with logging for monitoring."""

277

278

if isinstance(exception, HTTPException):

279

# Log HTTP exceptions

280

logger.warning(

281

f"HTTP Exception: {exception.status_code} - {exception.detail} "

282

f"[{request.method} {request.url.path}]"

283

)

284

285

return Response(

286

status_code=exception.status_code,

287

headers={"Content-Type": "application/json"},

288

description=f'{{"error": "{exception.detail}"}}'

289

)

290

291

else:

292

# Log unexpected exceptions

293

logger.error(

294

f"Unhandled Exception: {type(exception).__name__} - {str(exception)} "

295

f"[{request.method} {request.url.path}]",

296

exc_info=True

297

)

298

299

return Response(

300

status_code=status_codes.HTTP_500_INTERNAL_SERVER_ERROR,

301

headers={"Content-Type": "application/json"},

302

description='{"error": "Internal server error"}'

303

)

304

305

@app.get("/test/<scenario>")

306

def test_exceptions(request):

307

scenario = request.path_params["scenario"]

308

309

scenarios = {

310

"http_400": lambda: HTTPException(400, "Bad request test"),

311

"http_404": lambda: HTTPException(404, "Not found test"),

312

"http_500": lambda: HTTPException(500, "Server error test"),

313

"runtime": lambda: RuntimeError("Runtime error test"),

314

"value": lambda: ValueError("Value error test"),

315

}

316

317

if scenario in scenarios:

318

raise scenarios[scenario]()

319

else:

320

return {"message": f"Unknown scenario: {scenario}"}

321

322

app.start()

323

```