0
# HTTP Interface
1
2
HTTP server integration providing REST API endpoints with request/response handling, URL routing, WebSocket support, and integration with external web frameworks.
3
4
## Capabilities
5
6
### HTTP Endpoint Decorator
7
8
Decorator that exposes service methods as HTTP endpoints with flexible routing, method handling, and middleware support.
9
10
```python { .api }
11
def http(method, url, **kwargs):
12
"""
13
Decorator to expose a service method as an HTTP endpoint.
14
15
Parameters:
16
- method: HTTP method ('GET', 'POST', 'PUT', 'DELETE', etc.)
17
- url: URL pattern with optional path parameters
18
- expected_exceptions: Tuple of exceptions to convert to HTTP errors
19
- cors: CORS configuration dictionary
20
21
Returns:
22
Decorated method that handles HTTP requests
23
"""
24
```
25
26
**Usage Example:**
27
28
```python
29
from nameko.web.handlers import http
30
from nameko.rpc import RpcProxy
31
import json
32
33
class UserAPIService:
34
name = "user_api"
35
36
user_rpc = RpcProxy('user_service')
37
38
@http('GET', '/users/<int:user_id>')
39
def get_user(self, request, user_id):
40
"""Get user by ID"""
41
try:
42
user = self.user_rpc.get_user(user_id)
43
return json.dumps(user)
44
except Exception as e:
45
return {'error': str(e)}, 404
46
47
@http('POST', '/users')
48
def create_user(self, request):
49
"""Create a new user"""
50
user_data = json.loads(request.get_data())
51
52
# Validate required fields
53
if not user_data.get('email'):
54
return {'error': 'Email is required'}, 400
55
56
user = self.user_rpc.create_user(user_data)
57
return json.dumps(user), 201
58
59
@http('PUT', '/users/<int:user_id>')
60
def update_user(self, request, user_id):
61
"""Update existing user"""
62
user_data = json.loads(request.get_data())
63
user = self.user_rpc.update_user(user_id, user_data)
64
return json.dumps(user)
65
66
@http('DELETE', '/users/<int:user_id>')
67
def delete_user(self, request, user_id):
68
"""Delete user"""
69
self.user_rpc.delete_user(user_id)
70
return '', 204
71
```
72
73
### Request Object
74
75
HTTP handlers receive a request object containing all HTTP request information.
76
77
```python { .api }
78
# Request object attributes and methods
79
class Request:
80
"""
81
HTTP request object passed to HTTP handlers.
82
83
Attributes:
84
- method: HTTP method (GET, POST, etc.)
85
- url: Request URL
86
- headers: Request headers dictionary
87
- args: Query string parameters
88
- form: Form data for POST requests
89
- json: Parsed JSON data
90
- files: Uploaded files
91
- cookies: Request cookies
92
"""
93
94
def get_data(self, as_text=False):
95
"""Get raw request body data"""
96
97
def get_json(self):
98
"""Parse request body as JSON"""
99
```
100
101
**Request Handling Example:**
102
103
```python
104
@http('POST', '/api/upload')
105
def handle_upload(self, request):
106
# Access different request components
107
content_type = request.headers.get('Content-Type')
108
query_params = request.args
109
110
if content_type == 'application/json':
111
data = request.get_json()
112
return self._process_json(data)
113
elif 'multipart/form-data' in content_type:
114
files = request.files
115
form_data = request.form
116
return self._process_upload(files, form_data)
117
else:
118
raw_data = request.get_data(as_text=True)
119
return self._process_raw(raw_data)
120
```
121
122
### Response Handling
123
124
HTTP handlers can return various response formats with status codes and headers.
125
126
**Response Format Options:**
127
128
```python
129
@http('GET', '/api/data')
130
def get_data(self, request):
131
# Return string
132
return "Hello World"
133
134
# Return JSON (auto-serialized)
135
return {'message': 'Hello World'}
136
137
# Return with status code
138
return {'error': 'Not found'}, 404
139
140
# Return with status code and headers
141
return (
142
{'data': 'value'},
143
200,
144
{'Content-Type': 'application/json', 'X-Custom': 'header'}
145
)
146
147
# Return Response object for full control
148
from werkzeug.wrappers import Response
149
return Response(
150
json.dumps({'data': 'value'}),
151
status=200,
152
headers={'Content-Type': 'application/json'}
153
)
154
```
155
156
### URL Routing and Parameters
157
158
Flexible URL routing with path parameters, query parameters, and pattern matching.
159
160
```python
161
class APIService:
162
name = "api_service"
163
164
# Path parameters with type conversion
165
@http('GET', '/users/<int:user_id>')
166
def get_user(self, request, user_id):
167
# user_id is automatically converted to int
168
pass
169
170
# Multiple path parameters
171
@http('GET', '/users/<int:user_id>/posts/<int:post_id>')
172
def get_user_post(self, request, user_id, post_id):
173
pass
174
175
# String parameters (default)
176
@http('GET', '/categories/<category_name>')
177
def get_category(self, request, category_name):
178
pass
179
180
# UUID parameters
181
@http('GET', '/orders/<uuid:order_id>')
182
def get_order(self, request, order_id):
183
pass
184
185
# Query parameters
186
@http('GET', '/search')
187
def search(self, request):
188
query = request.args.get('q', '')
189
limit = int(request.args.get('limit', 10))
190
offset = int(request.args.get('offset', 0))
191
return self._search(query, limit, offset)
192
```
193
194
### CORS Support
195
196
Cross-Origin Resource Sharing (CORS) configuration for browser-based applications.
197
198
```python { .api }
199
@http('GET', '/api/data', cors={
200
'origins': ['http://localhost:3000', 'https://myapp.com'],
201
'methods': ['GET', 'POST', 'PUT', 'DELETE'],
202
'headers': ['Content-Type', 'Authorization'],
203
'credentials': True
204
})
205
def api_endpoint(self, request):
206
"""Endpoint with CORS configuration"""
207
```
208
209
### WebSocket Support
210
211
WebSocket RPC endpoints for real-time bidirectional communication with connection management and room-based messaging.
212
213
```python { .api }
214
from nameko.web.websocket import rpc as websocket_rpc, WebSocketHubProvider
215
216
@websocket_rpc
217
def websocket_method(socket_id, *args, **kwargs):
218
"""
219
Decorator for WebSocket RPC methods.
220
221
Parameters:
222
- socket_id: Unique identifier for the WebSocket connection
223
- *args, **kwargs: Method arguments
224
225
Returns:
226
Method result sent back to the WebSocket client
227
"""
228
229
class WebSocketHubProvider:
230
"""
231
Dependency provider for WebSocket hub functionality.
232
Manages WebSocket connections, rooms, and messaging.
233
"""
234
235
class WebSocketHub:
236
"""
237
Hub for managing WebSocket connections and broadcasting messages.
238
"""
239
240
def subscribe(self, socket_id, channel):
241
"""
242
Subscribe a WebSocket connection to a channel.
243
244
Parameters:
245
- socket_id: WebSocket connection identifier
246
- channel: Channel name to subscribe to
247
"""
248
249
def unsubscribe(self, socket_id, channel):
250
"""
251
Unsubscribe a WebSocket connection from a channel.
252
253
Parameters:
254
- socket_id: WebSocket connection identifier
255
- channel: Channel name to unsubscribe from
256
"""
257
258
def broadcast(self, channel, event, data):
259
"""
260
Broadcast a message to all connections subscribed to a channel.
261
262
Parameters:
263
- channel: Channel name to broadcast to
264
- event: Event name/type
265
- data: Message data to send
266
"""
267
268
def unicast(self, socket_id, event, data):
269
"""
270
Send a message to a specific WebSocket connection.
271
272
Parameters:
273
- socket_id: Target WebSocket connection identifier
274
- event: Event name/type
275
- data: Message data to send
276
"""
277
278
def get_subscriptions(self, socket_id):
279
"""
280
Get list of channels a WebSocket connection is subscribed to.
281
282
Parameters:
283
- socket_id: WebSocket connection identifier
284
285
Returns:
286
List of channel names
287
"""
288
```
289
290
**Usage Example:**
291
292
```python
293
from nameko.web.websocket import rpc as websocket_rpc, WebSocketHubProvider
294
from nameko.exceptions import ConnectionNotFound
295
296
class ChatService:
297
name = "chat_service"
298
299
websocket_hub = WebSocketHubProvider()
300
301
@websocket_rpc
302
def join_room(self, socket_id, room_id):
303
"""Subscribe socket to a chat room"""
304
self.websocket_hub.subscribe(socket_id, f'room:{room_id}')
305
306
# Notify other room members
307
self.websocket_hub.broadcast(f'room:{room_id}', 'user_joined', {
308
'socket_id': socket_id,
309
'room_id': room_id,
310
'timestamp': time.time()
311
})
312
313
return {'status': 'joined', 'room_id': room_id}
314
315
@websocket_rpc
316
def leave_room(self, socket_id, room_id):
317
"""Unsubscribe socket from a chat room"""
318
self.websocket_hub.unsubscribe(socket_id, f'room:{room_id}')
319
320
# Notify other room members
321
self.websocket_hub.broadcast(f'room:{room_id}', 'user_left', {
322
'socket_id': socket_id,
323
'room_id': room_id,
324
'timestamp': time.time()
325
})
326
327
return {'status': 'left', 'room_id': room_id}
328
329
@websocket_rpc
330
def send_message(self, socket_id, room_id, message):
331
"""Send message to all members of a chat room"""
332
try:
333
# Broadcast message to room
334
self.websocket_hub.broadcast(f'room:{room_id}', 'new_message', {
335
'message': message,
336
'sender': socket_id,
337
'room_id': room_id,
338
'timestamp': time.time()
339
})
340
return {'status': 'sent'}
341
except ConnectionNotFound:
342
return {'status': 'error', 'message': 'Socket not found'}
343
344
@websocket_rpc
345
def private_message(self, sender_id, target_id, message):
346
"""Send private message to specific user"""
347
try:
348
# Send direct message to target socket
349
self.websocket_hub.unicast(target_id, 'private_message', {
350
'message': message,
351
'sender': sender_id,
352
'timestamp': time.time()
353
})
354
return {'status': 'sent'}
355
except ConnectionNotFound:
356
return {'status': 'error', 'message': 'Target user not connected'}
357
358
@websocket_rpc
359
def get_my_rooms(self, socket_id):
360
"""Get list of rooms the socket is subscribed to"""
361
subscriptions = self.websocket_hub.get_subscriptions(socket_id)
362
rooms = [sub.replace('room:', '') for sub in subscriptions if sub.startswith('room:')]
363
return {'rooms': rooms}
364
```
365
366
**WebSocket Exceptions:**
367
368
```python { .api }
369
class ConnectionNotFound(NamekoException):
370
"""
371
Raised when attempting to send message to unknown WebSocket connection.
372
373
Parameters:
374
- socket_id: The unknown socket identifier
375
"""
376
```
377
378
### Error Handling
379
380
HTTP-specific error handling and exception mapping.
381
382
```python { .api }
383
from nameko.exceptions import BadRequest, NotFound, Forbidden
384
385
class APIErrorHandler:
386
387
@http('POST', '/api/users', expected_exceptions=(BadRequest, NotFound))
388
def create_user_endpoint(self, request):
389
try:
390
data = request.get_json()
391
if not data.get('email'):
392
raise BadRequest("Email is required")
393
394
user = self.user_service.get_user_by_email(data['email'])
395
if user:
396
raise BadRequest("User already exists")
397
398
return self.user_service.create_user(data)
399
400
except BadRequest as e:
401
return {'error': str(e)}, 400
402
except NotFound as e:
403
return {'error': str(e)}, 404
404
except Exception as e:
405
return {'error': 'Internal server error'}, 500
406
```
407
408
### Middleware and Request Processing
409
410
HTTP services support middleware for request preprocessing, authentication, and response modification.
411
412
```python
413
from nameko.web.handlers import http
414
415
class AuthenticatedAPIService:
416
name = "authenticated_api"
417
418
def _authenticate_request(self, request):
419
"""Middleware-style authentication"""
420
token = request.headers.get('Authorization', '').replace('Bearer ', '')
421
if not token:
422
return None, ('Unauthorized', 401)
423
424
# Validate token logic
425
user = self._validate_token(token)
426
if not user:
427
return None, ('Invalid token', 401)
428
429
return user, None
430
431
@http('GET', '/protected-data')
432
def get_protected_data(self, request):
433
user, error = self._authenticate_request(request)
434
if error:
435
return error
436
437
# Process authenticated request
438
return {'data': 'secret', 'user_id': user['id']}
439
```
440
441
### Configuration
442
443
HTTP service configuration options for server behavior, timeouts, and performance.
444
445
```python
446
# config.yaml
447
WEB_SERVER_ADDRESS: "0.0.0.0:8000"
448
WEB_SERVER_MAX_WORKERS: 10
449
WEB_SERVER_TIMEOUT: 30
450
451
# WebSocket configuration
452
WEBSOCKET_HUB_CONFIG:
453
max_connections: 1000
454
heartbeat_interval: 30
455
```