0
# HTTP API Handlers
1
2
Server-side HTTP request handlers for formatter discovery and code formatting operations with authentication, error handling, and caching support.
3
4
## Capabilities
5
6
### Formatters API Handler
7
8
Handles requests for discovering available code formatters.
9
10
```python { .api }
11
class FormattersAPIHandler(APIHandler):
12
@tornado.web.authenticated
13
def get(self) -> None:
14
"""Show what formatters are installed and available."""
15
pass
16
```
17
18
**Endpoint**: `GET /jupyterlab_code_formatter/formatters[?cached]`
19
20
**Query Parameters**:
21
- `cached` (optional) - Use cached formatter availability checks
22
23
**Response Format**:
24
```json
25
{
26
"formatters": {
27
"formatter_name": {
28
"enabled": boolean,
29
"label": "Human-readable name"
30
}
31
}
32
}
33
```
34
35
### Format API Handler
36
37
Handles code formatting requests.
38
39
```python { .api }
40
class FormatAPIHandler(APIHandler):
41
@tornado.web.authenticated
42
def post(self) -> None:
43
"""Format code using specified formatter."""
44
pass
45
```
46
47
**Endpoint**: `POST /jupyterlab_code_formatter/format[?cached]`
48
49
**Request Body**:
50
```json
51
{
52
"code": ["string array of code"],
53
"formatter": "formatter_name",
54
"notebook": boolean,
55
"options": {
56
"formatter_specific_options": "values"
57
}
58
}
59
```
60
61
**Response Format**:
62
```json
63
{
64
"code": [
65
{
66
"code": "formatted_code_string"
67
}
68
]
69
}
70
```
71
72
**Error Response**:
73
```json
74
{
75
"code": [
76
{
77
"error": "error_message"
78
}
79
]
80
}
81
```
82
83
### Handler Setup Function
84
85
Registers API handlers with the Jupyter server.
86
87
```python { .api }
88
def setup_handlers(web_app) -> None:
89
"""Register API handlers with Jupyter server."""
90
pass
91
```
92
93
**Parameters**:
94
- `web_app` - Tornado web application instance
95
96
## Usage Examples
97
98
### Handler Registration
99
100
```python
101
from jupyterlab_code_formatter.handlers import setup_handlers
102
103
def _load_jupyter_server_extension(server_app):
104
"""Register the API handlers to receive HTTP requests."""
105
setup_handlers(server_app.web_app)
106
server_app.log.info("Registered jupyterlab_code_formatter server extension")
107
```
108
109
### Request Processing Flow
110
111
#### Formatters Discovery Request
112
113
```python
114
# Client request: GET /jupyterlab_code_formatter/formatters
115
# Handler processes request:
116
117
def get(self) -> None:
118
use_cache = self.get_query_argument("cached", default=None)
119
120
response_data = {
121
"formatters": {
122
name: {
123
"enabled": formatter.cached_importable if use_cache else formatter.importable,
124
"label": formatter.label,
125
}
126
for name, formatter in SERVER_FORMATTERS.items()
127
}
128
}
129
130
self.finish(json.dumps(response_data))
131
```
132
133
#### Code Formatting Request
134
135
```python
136
# Client request: POST /jupyterlab_code_formatter/format
137
# Handler processes request:
138
139
def post(self) -> None:
140
data = json.loads(self.request.body.decode("utf-8"))
141
formatter_instance = SERVER_FORMATTERS.get(data["formatter"])
142
use_cache = self.get_query_argument("cached", default=None)
143
144
if formatter_instance is None or not (
145
formatter_instance.cached_importable if use_cache else formatter_instance.importable
146
):
147
self.set_status(404, f"Formatter {data['formatter']} not found!")
148
self.finish()
149
return
150
151
notebook = data["notebook"]
152
options = data.get("options", {})
153
formatted_code = []
154
155
for code in data["code"]:
156
try:
157
result = formatter_instance.format_code(code, notebook, **options)
158
formatted_code.append({"code": result})
159
except Exception as e:
160
formatted_code.append({"error": str(e)})
161
162
self.finish(json.dumps({"code": formatted_code}))
163
```
164
165
## API Endpoints
166
167
### Get Available Formatters
168
169
**URL**: `/jupyterlab_code_formatter/formatters`
170
**Method**: `GET`
171
**Authentication**: Required (Jupyter token)
172
173
**Query Parameters**:
174
- `cached` (optional) - Enable cached availability checks
175
176
**Success Response (200)**:
177
```json
178
{
179
"formatters": {
180
"black": {
181
"enabled": true,
182
"label": "Apply Black Formatter"
183
},
184
"isort": {
185
"enabled": true,
186
"label": "Apply Isort Formatter"
187
},
188
"yapf": {
189
"enabled": false,
190
"label": "Apply YAPF Formatter"
191
}
192
}
193
}
194
```
195
196
**Example Requests**:
197
```bash
198
# Get current formatter availability
199
curl -H "Authorization: token YOUR_TOKEN" \
200
http://localhost:8888/jupyterlab_code_formatter/formatters
201
202
# Get cached formatter availability
203
curl -H "Authorization: token YOUR_TOKEN" \
204
http://localhost:8888/jupyterlab_code_formatter/formatters?cached
205
```
206
207
### Format Code
208
209
**URL**: `/jupyterlab_code_formatter/format`
210
**Method**: `POST`
211
**Authentication**: Required (Jupyter token)
212
**Content-Type**: `application/json`
213
214
**Query Parameters**:
215
- `cached` (optional) - Use cached formatter availability
216
217
**Request Body**:
218
```json
219
{
220
"code": [
221
"def hello():\n pass",
222
"import os\nimport sys"
223
],
224
"formatter": "black",
225
"notebook": true,
226
"options": {
227
"line_length": 88,
228
"string_normalization": true
229
}
230
}
231
```
232
233
**Success Response (200)**:
234
```json
235
{
236
"code": [
237
{
238
"code": "def hello():\n pass\n"
239
},
240
{
241
"code": "import os\nimport sys\n"
242
}
243
]
244
}
245
```
246
247
**Error Response (200 with errors)**:
248
```json
249
{
250
"code": [
251
{
252
"error": "cannot use --safe with this Python version"
253
}
254
]
255
}
256
```
257
258
**Formatter Not Found (404)**:
259
```
260
Formatter unknown_formatter not found!
261
```
262
263
**Example Request**:
264
```bash
265
curl -X POST \
266
-H "Authorization: token YOUR_TOKEN" \
267
-H "Content-Type: application/json" \
268
-d '{
269
"code": ["def hello():\n pass"],
270
"formatter": "black",
271
"notebook": true,
272
"options": {"line_length": 88}
273
}' \
274
http://localhost:8888/jupyterlab_code_formatter/format
275
```
276
277
## Authentication and Security
278
279
### Jupyter Authentication
280
281
Both handlers use Tornado's `@tornado.web.authenticated` decorator:
282
283
- **Token-based**: Uses Jupyter server's authentication system
284
- **Automatic**: Authentication handled by base APIHandler class
285
- **Secure**: Prevents unauthorized access to formatting capabilities
286
287
### Input Validation
288
289
Request processing includes validation:
290
291
- **JSON Parsing**: Validates request body is valid JSON
292
- **Required Fields**: Checks for required fields in request data
293
- **Formatter Existence**: Validates requested formatter exists
294
- **Sanitization**: Processes user input safely
295
296
### Error Handling
297
298
Comprehensive error handling:
299
300
- **HTTP Status Codes**: Appropriate status codes for different error types
301
- **Error Messages**: Clear error descriptions in responses
302
- **Exception Handling**: Graceful handling of formatter exceptions
303
- **Logging**: Error logging for debugging and monitoring
304
305
## Handler Configuration
306
307
### URL Pattern Registration
308
309
```python
310
def setup_handlers(web_app):
311
host_pattern = ".*$"
312
base_url = web_app.settings["base_url"]
313
314
# Register formatters endpoint
315
web_app.add_handlers(
316
host_pattern,
317
[
318
(
319
url_path_join(base_url, "jupyterlab_code_formatter/formatters"),
320
FormattersAPIHandler,
321
)
322
],
323
)
324
325
# Register format endpoint
326
web_app.add_handlers(
327
host_pattern,
328
[
329
(
330
url_path_join(base_url, "/jupyterlab_code_formatter/format"),
331
FormatAPIHandler,
332
)
333
],
334
)
335
```
336
337
### Base URL Handling
338
339
Handlers respect JupyterLab's base URL configuration:
340
341
- **Dynamic Base URL**: Uses `web_app.settings["base_url"]`
342
- **URL Construction**: Uses `url_path_join()` for proper URL construction
343
- **Flexible Deployment**: Works with different JupyterLab deployment configurations
344
345
## Performance Considerations
346
347
### Caching Support
348
349
Both handlers support caching for improved performance:
350
351
- **Query Parameter**: `?cached` enables cached checks
352
- **Formatter Availability**: Caches `importable` property checks
353
- **Persistent Cache**: Cache persists for server session duration
354
- **Selective Caching**: Can enable caching per request
355
356
### Asynchronous Processing
357
358
Handlers are designed for async operation:
359
360
- **Non-blocking**: Formatters run without blocking server
361
- **Concurrent Requests**: Multiple formatting requests can be processed
362
- **Resource Management**: Proper cleanup of formatter processes
363
364
### Error Recovery
365
366
Robust error handling ensures server stability:
367
368
- **Isolated Errors**: Formatter errors don't crash server
369
- **Partial Success**: Individual code blocks can fail independently
370
- **Graceful Degradation**: Server continues operating with failed formatters