0
# Server Command
1
2
> **NOTE**: This is a CLI-only command. @finos/calm-cli does not export functions for programmatic use.
3
4
The `server` command starts an HTTP server providing REST API access to CALM validation operations. This experimental feature enables programmatic validation through HTTP requests, useful for integrating CALM validation into web applications, microservices, or CI/CD pipelines.
5
6
## Capabilities
7
8
### Server Command
9
10
Start an HTTP server to provide REST API access to validation operations.
11
12
```typescript { .api }
13
/**
14
* Start a HTTP server to proxy CLI commands (experimental)
15
* @command calm server [options]
16
*/
17
interface ServerCommandOptions {
18
/** Server port
19
* CLI flags: --port <port>
20
* Default: "3000"
21
*/
22
port?: string;
23
24
/** Path to directory containing meta schemas
25
* CLI flags: -s, --schema-directory <path>
26
* Required: yes
27
*/
28
schemaDirectory: string;
29
30
/** Enable verbose logging
31
* CLI flags: -v, --verbose
32
* Default: false
33
*/
34
verbose?: boolean;
35
}
36
```
37
38
**Usage Examples:**
39
40
```bash
41
# Start server on default port 3000
42
calm server -s ./calm/schemas
43
44
# Start server on custom port
45
calm server --port 8080 -s ./calm/schemas
46
47
# Start with verbose logging
48
calm server --port 3000 -s ./calm/schemas -v
49
```
50
51
## API Endpoints
52
53
### Health Check
54
55
Check server health status.
56
57
```typescript { .api }
58
/**
59
* GET /health
60
* Health check endpoint
61
* @returns StatusResponse with status "OK"
62
*/
63
interface HealthCheckEndpoint {
64
method: 'GET';
65
path: '/health';
66
response: StatusResponse;
67
}
68
69
interface StatusResponse {
70
status: string; // "OK"
71
}
72
```
73
74
**Example Request:**
75
76
```bash
77
curl http://localhost:3000/health
78
```
79
80
**Example Response:**
81
82
```json
83
{
84
"status": "OK"
85
}
86
```
87
88
### Validate Architecture
89
90
Validate a CALM architecture against its embedded schema.
91
92
```typescript { .api }
93
/**
94
* POST /calm/validate
95
* Validate CALM architecture
96
* @rateLimit 100 requests per 15 minutes per IP
97
* @returns ValidationOutcome on success or ErrorResponse on failure
98
*/
99
interface ValidateEndpoint {
100
method: 'POST';
101
path: '/calm/validate';
102
headers: {
103
'Content-Type': 'application/json';
104
};
105
body: ValidationRequest;
106
response: ValidationOutcome | ErrorResponse;
107
statusCodes: {
108
201: 'Validation completed successfully';
109
400: 'Invalid request (missing $schema, invalid JSON)';
110
429: 'Rate limit exceeded';
111
500: 'Server error (schema loading failed, validation error)';
112
};
113
}
114
115
interface ValidationRequest {
116
/** JSON string containing CALM architecture */
117
architecture: string;
118
}
119
120
interface ErrorResponse {
121
error: string;
122
}
123
```
124
125
**Example Request:**
126
127
```bash
128
curl -X POST http://localhost:3000/calm/validate \
129
-H "Content-Type: application/json" \
130
-d '{
131
"architecture": "{\"$schema\":\"https://calm.finos.org/schemas/calm-v1.json\",\"nodes\":[]}"
132
}'
133
```
134
135
**Example Success Response (201):**
136
137
```json
138
{
139
"jsonSchemaValidationOutputs": [],
140
"spectralSchemaValidationOutputs": [],
141
"hasErrors": false,
142
"hasWarnings": false
143
}
144
```
145
146
**Example Error Response (400):**
147
148
```json
149
{
150
"error": "The \"$schema\" field is missing from the request body"
151
}
152
```
153
154
**Example Error Response (429):**
155
156
```json
157
{
158
"error": "Too many requests, please try again later."
159
}
160
```
161
162
## Configuration
163
164
### CALMHub Integration
165
166
The server command uses CALMHub URL from the user configuration file for remote pattern and schema loading:
167
168
**Via User Configuration File (`~/.calm.json`):**
169
170
```json
171
{
172
"calmHubUrl": "https://calmhub.example.com"
173
}
174
```
175
176
**Important Distinction from Generate Command:**
177
178
Unlike the `generate` command which accepts both a `-c, --calm-hub-url` command-line option and configuration file setting, the **server command does NOT accept `--calm-hub-url` as a command-line option**. The server will **only** use the CALMHub URL from the `~/.calm.json` configuration file if present.
179
180
**Rationale:** The server needs a consistent configuration that doesn't change per-request. Since the server runs continuously and handles multiple validation requests, having a stable, file-based configuration is more appropriate than per-invocation command-line options.
181
182
**To configure CALMHub for the server:**
183
1. Create or edit `~/.calm.json` in your home directory
184
2. Add the `calmHubUrl` property with your CALMHub instance URL
185
3. Restart the server to pick up the new configuration
186
187
## Rate Limiting
188
189
The validation endpoint includes rate limiting to prevent abuse:
190
191
- **Limit:** 100 requests per 15 minutes per IP address
192
- **Response:** 429 Too Many Requests when limit exceeded
193
- **Headers:** Rate limit information included in response headers
194
195
## Server Architecture
196
197
### Express Application Structure
198
199
```typescript { .api }
200
/**
201
* Express router configuration for all server routes
202
*/
203
class CLIServerRoutes {
204
router: Router;
205
206
/**
207
* @param schemaDirectory - SchemaDirectory instance for validation
208
* @param debug - Enable debug logging (default: false)
209
*/
210
constructor(schemaDirectory: SchemaDirectory, debug?: boolean);
211
}
212
213
/**
214
* Express router for validation API endpoint
215
* Includes rate limiting and error handling
216
*/
217
class ValidationRouter {
218
/**
219
* @param router - Express Router instance
220
* @param schemaDirectory - SchemaDirectory instance for validation
221
* @param debug - Enable debug logging (default: false)
222
*/
223
constructor(
224
router: Router,
225
schemaDirectory: SchemaDirectory,
226
debug?: boolean
227
);
228
}
229
230
/**
231
* Express router for health check endpoint
232
*/
233
class HealthRouter {
234
/**
235
* @param router - Express Router instance
236
*/
237
constructor(router: Router);
238
}
239
```
240
241
## Request/Response Flow
242
243
### Validation Request Flow
244
245
1. **Request Received:** POST request to `/calm/validate`
246
2. **Rate Limit Check:** Verify IP hasn't exceeded rate limit
247
3. **JSON Parsing:** Parse architecture from request body
248
4. **Schema Extraction:** Extract `$schema` field from architecture
249
5. **Schema Loading:** Load and validate schema from SchemaDirectory
250
6. **Validation:** Perform JSON schema and Spectral validation
251
7. **Response:** Return ValidationOutcome or ErrorResponse
252
253
### Error Scenarios
254
255
**Missing $schema Field:**
256
```json
257
{
258
"error": "The \"$schema\" field is missing from the request body"
259
}
260
```
261
262
**Invalid JSON:**
263
```json
264
{
265
"error": "Invalid JSON format for architecture"
266
}
267
```
268
269
**Schema Not Available:**
270
```json
271
{
272
"error": "The \"$schema\" field referenced is not available to the server"
273
}
274
```
275
276
**Validation Failed:**
277
```json
278
{
279
"error": "Validation error message"
280
}
281
```
282
283
## Integration Examples
284
285
### Node.js Client
286
287
```typescript
288
import axios from 'axios';
289
290
async function validateArchitecture(architecture: object) {
291
try {
292
const response = await axios.post('http://localhost:3000/calm/validate', {
293
architecture: JSON.stringify(architecture)
294
});
295
296
console.log('Validation result:', response.data);
297
return response.data;
298
} catch (error) {
299
if (error.response) {
300
console.error('Validation failed:', error.response.data.error);
301
} else {
302
console.error('Request failed:', error.message);
303
}
304
throw error;
305
}
306
}
307
308
// Usage
309
const myArchitecture = {
310
"$schema": "https://calm.finos.org/schemas/calm-v1.json",
311
"nodes": [
312
{
313
"unique-id": "api-gateway",
314
"node-type": "system",
315
"name": "API Gateway"
316
}
317
]
318
};
319
320
await validateArchitecture(myArchitecture);
321
```
322
323
### Python Client
324
325
```python
326
import requests
327
import json
328
329
def validate_architecture(architecture):
330
url = 'http://localhost:3000/calm/validate'
331
headers = {'Content-Type': 'application/json'}
332
payload = {
333
'architecture': json.dumps(architecture)
334
}
335
336
response = requests.post(url, json=payload, headers=headers)
337
338
if response.status_code == 201:
339
return response.json()
340
else:
341
raise Exception(f"Validation failed: {response.json()['error']}")
342
343
# Usage
344
my_architecture = {
345
"$schema": "https://calm.finos.org/schemas/calm-v1.json",
346
"nodes": []
347
}
348
349
result = validate_architecture(my_architecture)
350
print("Validation result:", result)
351
```
352
353
### cURL Examples
354
355
```bash
356
# Valid architecture
357
curl -X POST http://localhost:3000/calm/validate \
358
-H "Content-Type: application/json" \
359
-d @- << 'EOF'
360
{
361
"architecture": "{\"$schema\":\"https://calm.finos.org/schemas/calm-v1.json\",\"nodes\":[]}"
362
}
363
EOF
364
365
# Architecture with validation errors
366
curl -X POST http://localhost:3000/calm/validate \
367
-H "Content-Type: application/json" \
368
-d '{"architecture": "{\"nodes\":[]}"}'
369
370
# Health check
371
curl http://localhost:3000/health
372
```
373
374
## Configuration
375
376
### Schema Directory
377
378
The server requires a schema directory containing CALM meta schemas:
379
380
```bash
381
calm server -s ./calm/release
382
```
383
384
The schema directory should contain:
385
- Meta schemas for CALM architecture validation
386
- Pattern schemas
387
- Any custom schemas
388
389
### Port Configuration
390
391
Default port is 3000, but can be customized:
392
393
```bash
394
calm server --port 8080 -s ./schemas
395
```
396
397
**Important:** Ensure the port is not already in use by another application.
398
399
### Verbose Logging
400
401
Enable verbose logging for debugging:
402
403
```bash
404
calm server --port 3000 -s ./schemas -v
405
```
406
407
Verbose mode logs:
408
- Schema loading operations
409
- Validation requests and results
410
- Error details
411
412
## Deployment Considerations
413
414
### Production Deployment
415
416
For production use, consider:
417
418
1. **Reverse Proxy:** Use nginx or Apache as reverse proxy
419
2. **HTTPS:** Enable SSL/TLS for secure communication
420
3. **Authentication:** Add authentication middleware
421
4. **Rate Limiting:** Adjust rate limits based on usage patterns
422
5. **Monitoring:** Add application monitoring and health checks
423
6. **Process Management:** Use PM2 or systemd for process management
424
425
### Docker Deployment
426
427
Example Dockerfile:
428
429
```dockerfile
430
FROM node:18-alpine
431
432
WORKDIR /app
433
434
# Install CALM CLI
435
RUN npm install -g @finos/calm-cli
436
437
# Copy schemas
438
COPY ./schemas /app/schemas
439
440
# Expose port
441
EXPOSE 3000
442
443
# Start server
444
CMD ["calm", "server", "--port", "3000", "-s", "/app/schemas"]
445
```
446
447
### Kubernetes Deployment
448
449
Example Kubernetes manifest:
450
451
```yaml
452
apiVersion: apps/v1
453
kind: Deployment
454
metadata:
455
name: calm-server
456
spec:
457
replicas: 3
458
selector:
459
matchLabels:
460
app: calm-server
461
template:
462
metadata:
463
labels:
464
app: calm-server
465
spec:
466
containers:
467
- name: calm-server
468
image: calm-server:latest
469
ports:
470
- containerPort: 3000
471
env:
472
- name: PORT
473
value: "3000"
474
---
475
apiVersion: v1
476
kind: Service
477
metadata:
478
name: calm-server
479
spec:
480
selector:
481
app: calm-server
482
ports:
483
- port: 80
484
targetPort: 3000
485
type: LoadBalancer
486
```
487
488
## Limitations
489
490
**Experimental Feature:**
491
The server command is marked as experimental and may have limitations:
492
493
1. **Pattern Validation Not Supported:** Server only validates against embedded `$schema`, not separate pattern files
494
2. **No Authentication:** No built-in authentication or authorization
495
3. **Limited Output Formats:** Only JSON output format supported
496
4. **Basic Rate Limiting:** Simple IP-based rate limiting without persistence
497
498
**Use Cases:**
499
- Development and testing environments
500
- Internal microservice integration
501
- CI/CD pipeline integration
502
- Web application backends
503
504
**Not Recommended For:**
505
- Public internet exposure without additional security
506
- High-traffic production environments without load balancing
507
- Scenarios requiring pattern-based validation (use CLI directly)
508
509
## Error Handling
510
511
### Server Startup Errors
512
513
**Port Already in Use:**
514
```
515
Error: listen EADDRINUSE: address already in use :::3000
516
```
517
**Solution:** Use a different port or stop the conflicting process.
518
519
**Schema Directory Not Found:**
520
```
521
Error: ENOENT: no such file or directory
522
```
523
**Solution:** Verify schema directory path is correct.
524
525
**Permission Denied:**
526
```
527
Error: listen EACCES: permission denied
528
```
529
**Solution:** Use a port number > 1024 or run with appropriate permissions.
530
531
### Runtime Errors
532
533
All runtime errors are caught and returned as ErrorResponse with appropriate HTTP status codes. The server remains running and available for subsequent requests.
534
535
## Monitoring
536
537
### Health Check Monitoring
538
539
Use the `/health` endpoint for uptime monitoring:
540
541
```bash
542
# Simple health check
543
curl -f http://localhost:3000/health || echo "Server down"
544
545
# With monitoring tool
546
watch -n 30 'curl -s http://localhost:3000/health | jq .status'
547
```
548
549
### Logging
550
551
The server logs important events:
552
- Server startup and port binding
553
- Schema loading success/failure
554
- Validation requests (in verbose mode)
555
- Errors and warnings
556
557
Access logs through the application's stdout/stderr.
558