jsgui3-server 0.0.138 → 0.0.140

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (57) hide show
  1. package/AGENTS.md +87 -0
  2. package/README.md +12 -0
  3. package/docs/GUIDE_TO_AGENTIC_WORKFLOWS_BY_GROK.md +19 -0
  4. package/docs/advanced-usage-examples.md +1360 -0
  5. package/docs/agent-development-guide.md +386 -0
  6. package/docs/api-reference.md +916 -0
  7. package/docs/broken-functionality-tracker.md +285 -0
  8. package/docs/bundling-system-deep-dive.md +525 -0
  9. package/docs/cli-reference.md +393 -0
  10. package/docs/comprehensive-documentation.md +1403 -0
  11. package/docs/configuration-reference.md +808 -0
  12. package/docs/controls-development.md +859 -0
  13. package/docs/documentation-review/CURRENT_REVIEW.md +95 -0
  14. package/docs/function-publishers-json-apis.md +847 -0
  15. package/docs/getting-started-with-json.md +518 -0
  16. package/docs/minification-compression-sourcemaps-status.md +482 -0
  17. package/docs/minification-compression-sourcemaps-test-results.md +205 -0
  18. package/docs/publishers-guide.md +313 -0
  19. package/docs/resources-guide.md +615 -0
  20. package/docs/serve-helpers.md +406 -0
  21. package/docs/simple-server-api-design.md +13 -0
  22. package/docs/system-architecture.md +275 -0
  23. package/docs/troubleshooting.md +698 -0
  24. package/examples/json/README.md +115 -0
  25. package/examples/json/basic-api/README.md +345 -0
  26. package/examples/json/basic-api/server.js +199 -0
  27. package/examples/json/simple-api/README.md +125 -0
  28. package/examples/json/simple-api/diagnostic-report.json +73 -0
  29. package/examples/json/simple-api/diagnostic-test.js +433 -0
  30. package/examples/json/simple-api/server-debug.md +58 -0
  31. package/examples/json/simple-api/server.js +91 -0
  32. package/examples/json/simple-api/test.js +215 -0
  33. package/http/responders/static/Static_Route_HTTP_Responder.js +1 -2
  34. package/package.json +19 -8
  35. package/publishers/helpers/assigners/static-compressed-response-buffers/Single_Control_Webpage_Server_Static_Compressed_Response_Buffers_Assigner.js +65 -12
  36. package/publishers/helpers/preparers/static/bundle/Static_Routes_Responses_Webpage_Bundle_Preparer.js +6 -1
  37. package/publishers/http-function-publisher.js +59 -38
  38. package/publishers/http-webpage-publisher.js +48 -1
  39. package/resources/processors/bundlers/js/esbuild/Advanced_JS_Bundler_Using_ESBuild.js +38 -146
  40. package/resources/processors/bundlers/js/esbuild/Core_JS_Non_Minifying_Bundler_Using_ESBuild.js +54 -5
  41. package/resources/processors/bundlers/js/esbuild/Core_JS_Single_File_Minifying_Bundler_Using_ESBuild.js +36 -4
  42. package/serve-factory.js +36 -9
  43. package/server.js +10 -4
  44. package/test-report.json +0 -0
  45. package/tests/README.md +250 -0
  46. package/tests/assigners.test.js +316 -0
  47. package/tests/bundlers.test.js +329 -0
  48. package/tests/configuration-validation.test.js +530 -0
  49. package/tests/content-analysis.test.js +641 -0
  50. package/tests/end-to-end.test.js +496 -0
  51. package/tests/error-handling.test.js +746 -0
  52. package/tests/performance.test.js +653 -0
  53. package/tests/publishers.test.js +395 -0
  54. package/tests/temp_invalid.js +7 -0
  55. package/tests/temp_invalid_utf8.js +1 -0
  56. package/tests/temp_malformed.js +10 -0
  57. package/tests/test-runner.js +261 -0
@@ -0,0 +1,847 @@
1
+ # Function Publishers and JSON APIs
2
+
3
+ ## When to Read
4
+
5
+ This document explains how to use JSGUI3 Server's function publishers to create JSON APIs. Read this when:
6
+ - You want to create RESTful JSON APIs with JSGUI3 Server
7
+ - You need to understand how function publishers work
8
+ - You're building backend services that return JSON data
9
+ - You want to integrate with frontend applications via HTTP APIs
10
+ - You need to handle different content types and HTTP methods
11
+
12
+ **Note:** For basic usage with `Server.serve()`, see [README.md](../README.md). For advanced examples, see [docs/advanced-usage-examples.md](docs/advanced-usage-examples.md).
13
+
14
+ ## Overview
15
+
16
+ JSGUI3 Server provides a powerful function publishing system that automatically creates HTTP endpoints from JavaScript functions. These publishers handle:
17
+
18
+ - **Automatic JSON serialization/deserialization**
19
+ - **Content-type negotiation** (JSON, text, promises)
20
+ - **HTTP method routing** (GET, POST, etc.)
21
+ - **Error handling and propagation**
22
+ - **Async/await support**
23
+
24
+ ## Function Publisher Architecture
25
+
26
+ ### Core Components
27
+
28
+ ```
29
+ HTTP Request → Function Publisher → Your Function → JSON Response
30
+ ↓ ↓ ↓ ↓
31
+ Content-Type → Parse Input → Execute → Serialize Output
32
+ application/json JSON Function JSON/text
33
+ ```
34
+
35
+ ### Publisher Types
36
+
37
+ 1. **Function Publisher** (`http-function-publisher.js`): Direct function-to-HTTP mapping
38
+ 2. **Resource Publisher** (`http-resource-publisher.js`): RESTful resource operations
39
+ 3. **API Integration**: Built into `Server.serve()` via the `api` option
40
+
41
+ ## Basic Function Publishing
42
+
43
+ ### Simple API Endpoint
44
+
45
+ ```javascript
46
+ const Server = require('jsgui3-server');
47
+
48
+ Server.serve({
49
+ ctrl: require('./client').controls.MyApp,
50
+
51
+ // Function publishers automatically create /api/* routes
52
+ api: {
53
+ // GET/POST /api/hello
54
+ 'hello': (name) => `Hello ${name || 'World'}!`,
55
+
56
+ // GET/POST /api/time
57
+ 'time': () => new Date().toISOString(),
58
+
59
+ // GET/POST /api/random
60
+ 'random': () => Math.random()
61
+ },
62
+
63
+ port: 3000
64
+ });
65
+ ```
66
+
67
+ **What happens:**
68
+ - Routes are automatically prefixed with `/api/`
69
+ - Functions receive parsed request body as first parameter
70
+ - Return values are automatically JSON-serialized
71
+ - HTTP status codes are set appropriately
72
+
73
+ ### Testing the API
74
+
75
+ ```bash
76
+ # Test the endpoints
77
+ curl http://localhost:3000/api/hello
78
+ # {"result":"Hello World!"}
79
+
80
+ curl -X POST http://localhost:3000/api/hello \
81
+ -H "Content-Type: application/json" \
82
+ -d '{"name":"Alice"}'
83
+ # {"result":"Hello Alice!"}
84
+
85
+ curl http://localhost:3000/api/time
86
+ # {"result":"2025-11-02T01:00:00.000Z"}
87
+ ```
88
+
89
+ ## Input Handling
90
+
91
+ ### Content Type Support
92
+
93
+ The function publisher automatically handles different content types:
94
+
95
+ #### JSON Input (`application/json`)
96
+ ```javascript
97
+ api: {
98
+ 'calculate': (data) => {
99
+ // data is already parsed JSON object
100
+ return {
101
+ sum: data.a + data.b,
102
+ product: data.a * data.b
103
+ };
104
+ }
105
+ }
106
+ ```
107
+
108
+ **Request:**
109
+ ```bash
110
+ curl -X POST http://localhost:3000/api/calculate \
111
+ -H "Content-Type: application/json" \
112
+ -d '{"a": 5, "b": 3}'
113
+ ```
114
+
115
+ **Response:**
116
+ ```json
117
+ {
118
+ "sum": 8,
119
+ "product": 15
120
+ }
121
+ ```
122
+
123
+ #### Text Input (`text/plain`)
124
+ ```javascript
125
+ api: {
126
+ 'echo': (text) => `Echo: ${text}`
127
+ }
128
+ ```
129
+
130
+ **Request:**
131
+ ```bash
132
+ curl -X POST http://localhost:3000/api/echo \
133
+ -H "Content-Type: text/plain" \
134
+ -d "Hello World"
135
+ ```
136
+
137
+ **Response:**
138
+ ```json
139
+ {
140
+ "result": "Echo: Hello World"
141
+ }
142
+ ```
143
+
144
+ #### No Body (GET requests)
145
+ ```javascript
146
+ api: {
147
+ 'status': () => ({
148
+ uptime: process.uptime(),
149
+ memory: process.memoryUsage(),
150
+ timestamp: new Date()
151
+ })
152
+ }
153
+ ```
154
+
155
+ **Request:**
156
+ ```bash
157
+ curl http://localhost:3000/api/status
158
+ ```
159
+
160
+ ## Output Handling
161
+
162
+ ### Return Type Detection
163
+
164
+ Functions can return different types, automatically handled by content-type detection:
165
+
166
+ #### Objects/Arrays → JSON
167
+ ```javascript
168
+ api: {
169
+ 'user': () => ({
170
+ id: 123,
171
+ name: "John Doe",
172
+ email: "john@example.com"
173
+ }),
174
+
175
+ 'users': () => [
176
+ { id: 1, name: "Alice" },
177
+ { id: 2, name: "Bob" }
178
+ ]
179
+ }
180
+ ```
181
+
182
+ #### Strings → Text
183
+ ```javascript
184
+ api: {
185
+ 'greeting': (name) => `Hello, ${name}!`
186
+ }
187
+ ```
188
+
189
+ #### Promises → Async Resolution
190
+ ```javascript
191
+ api: {
192
+ 'async-data': async () => {
193
+ const data = await fetchExternalAPI();
194
+ return data;
195
+ },
196
+
197
+ 'delayed': () => new Promise(resolve => {
198
+ setTimeout(() => resolve({ message: 'Done!' }), 1000);
199
+ })
200
+ }
201
+ ```
202
+
203
+ ## Advanced Patterns
204
+
205
+ ### Database Integration
206
+
207
+ ```javascript
208
+ // Simulated database
209
+ const db = {
210
+ users: [
211
+ { id: 1, name: 'Alice', email: 'alice@example.com' },
212
+ { id: 2, name: 'Bob', email: 'bob@example.com' }
213
+ ]
214
+ };
215
+
216
+ Server.serve({
217
+ ctrl: require('./client').controls.App,
218
+
219
+ api: {
220
+ // GET /api/users - List all users
221
+ 'users': () => db.users,
222
+
223
+ // GET /api/user?id=1 - Get specific user
224
+ 'user': ({ id }) => {
225
+ const user = db.users.find(u => u.id === parseInt(id));
226
+ if (!user) throw new Error('User not found');
227
+ return user;
228
+ },
229
+
230
+ // POST /api/user - Create new user
231
+ 'create-user': ({ name, email }) => {
232
+ const newUser = {
233
+ id: db.users.length + 1,
234
+ name,
235
+ email
236
+ };
237
+ db.users.push(newUser);
238
+ return { success: true, user: newUser };
239
+ },
240
+
241
+ // POST /api/update-user - Update existing user
242
+ 'update-user': ({ id, ...updates }) => {
243
+ const user = db.users.find(u => u.id === parseInt(id));
244
+ if (!user) throw new Error('User not found');
245
+
246
+ Object.assign(user, updates);
247
+ return { success: true, user };
248
+ }
249
+ },
250
+
251
+ port: 3000
252
+ });
253
+ ```
254
+
255
+ ### File Upload Handling
256
+
257
+ ```javascript
258
+ const fs = require('fs');
259
+ const path = require('path');
260
+
261
+ Server.serve({
262
+ ctrl: require('./client').controls.App,
263
+
264
+ api: {
265
+ // POST /api/upload - Handle file uploads
266
+ 'upload': async (files) => {
267
+ const uploadedFiles = [];
268
+
269
+ for (const file of files) {
270
+ const filename = `${Date.now()}-${file.filename}`;
271
+ const filepath = path.join(__dirname, 'uploads', filename);
272
+
273
+ // Ensure uploads directory exists
274
+ fs.mkdirSync(path.dirname(filepath), { recursive: true });
275
+
276
+ // Write file
277
+ fs.writeFileSync(filepath, file.buffer);
278
+
279
+ uploadedFiles.push({
280
+ originalName: file.filename,
281
+ savedName: filename,
282
+ size: file.buffer.length,
283
+ url: `/uploads/${filename}`
284
+ });
285
+ }
286
+
287
+ return {
288
+ success: true,
289
+ files: uploadedFiles
290
+ };
291
+ }
292
+ },
293
+
294
+ port: 3000
295
+ });
296
+ ```
297
+
298
+ ### Authentication and Authorization
299
+
300
+ ```javascript
301
+ const jwt = require('jsonwebtoken');
302
+ const bcrypt = require('bcrypt');
303
+
304
+ const JWT_SECRET = process.env.JWT_SECRET || 'your-secret-key';
305
+ const users = [
306
+ { id: 1, username: 'admin', passwordHash: '$2b$10$...' }
307
+ ];
308
+
309
+ Server.serve({
310
+ ctrl: require('./client').controls.App,
311
+
312
+ api: {
313
+ // POST /api/login
314
+ 'login': async ({ username, password }) => {
315
+ const user = users.find(u => u.username === username);
316
+ if (!user) throw new Error('Invalid credentials');
317
+
318
+ const validPassword = await bcrypt.compare(password, user.passwordHash);
319
+ if (!validPassword) throw new Error('Invalid credentials');
320
+
321
+ const token = jwt.sign(
322
+ { userId: user.id, username: user.username },
323
+ JWT_SECRET,
324
+ { expiresIn: '24h' }
325
+ );
326
+
327
+ return { token, user: { id: user.id, username: user.username } };
328
+ },
329
+
330
+ // POST /api/protected - Requires authentication
331
+ 'protected': (data, req) => {
332
+ // Extract token from request (implementation depends on auth middleware)
333
+ const authHeader = req.headers.authorization;
334
+ if (!authHeader || !authHeader.startsWith('Bearer ')) {
335
+ throw new Error('No token provided');
336
+ }
337
+
338
+ const token = authHeader.substring(7);
339
+ try {
340
+ const decoded = jwt.verify(token, JWT_SECRET);
341
+ return { message: 'Protected data', user: decoded };
342
+ } catch (error) {
343
+ throw new Error('Invalid token');
344
+ }
345
+ }
346
+ },
347
+
348
+ port: 3000
349
+ });
350
+ ```
351
+
352
+ ## Error Handling
353
+
354
+ ### Automatic Error Propagation
355
+
356
+ ```javascript
357
+ api: {
358
+ 'risky-operation': (params) => {
359
+ if (!params.requiredField) {
360
+ throw new Error('requiredField is required');
361
+ }
362
+
363
+ if (params.value < 0) {
364
+ throw new Error('Value must be positive');
365
+ }
366
+
367
+ return { result: params.value * 2 };
368
+ }
369
+ }
370
+ ```
371
+
372
+ **Error Response:**
373
+ ```json
374
+ {
375
+ "error": "requiredField is required"
376
+ }
377
+ ```
378
+
379
+ ### Custom Error Types
380
+
381
+ ```javascript
382
+ class ValidationError extends Error {
383
+ constructor(message, field) {
384
+ super(message);
385
+ this.name = 'ValidationError';
386
+ this.field = field;
387
+ this.statusCode = 400;
388
+ }
389
+ }
390
+
391
+ api: {
392
+ 'validate': (data) => {
393
+ if (!data.email || !data.email.includes('@')) {
394
+ throw new ValidationError('Invalid email format', 'email');
395
+ }
396
+
397
+ return { valid: true, email: data.email };
398
+ }
399
+ }
400
+ ```
401
+
402
+ ## Resource Publishers
403
+
404
+ ### RESTful Resource Operations
405
+
406
+ Resource publishers provide CRUD operations for data resources:
407
+
408
+ ```javascript
409
+ const { Resource } = require('jsgui3-html');
410
+
411
+ class UserResource extends Resource {
412
+ constructor(spec) {
413
+ super(spec);
414
+ this.users = [
415
+ { id: 1, name: 'Alice', email: 'alice@example.com' },
416
+ { id: 2, name: 'Bob', email: 'bob@example.com' }
417
+ ];
418
+ }
419
+
420
+ // GET /api/users
421
+ async get(pathParts) {
422
+ if (pathParts.length === 0) {
423
+ return this.users; // List all users
424
+ }
425
+
426
+ const id = parseInt(pathParts[0]);
427
+ const user = this.users.find(u => u.id === id);
428
+ if (!user) throw new Error('User not found');
429
+ return user; // Get specific user
430
+ }
431
+
432
+ // POST /api/users
433
+ async post(data) {
434
+ const newUser = {
435
+ id: this.users.length + 1,
436
+ name: data.name,
437
+ email: data.email
438
+ };
439
+ this.users.push(newUser);
440
+ return newUser;
441
+ }
442
+
443
+ // DELETE /api/users/1
444
+ async delete(pathParts) {
445
+ const id = parseInt(pathParts[0]);
446
+ const index = this.users.findIndex(u => u.id === id);
447
+ if (index === -1) throw new Error('User not found');
448
+
449
+ const deletedUser = this.users.splice(index, 1)[0];
450
+ return { deleted: true, user: deletedUser };
451
+ }
452
+ }
453
+
454
+ // In server setup
455
+ const userResource = new UserResource();
456
+ const resourcePublisher = new (require('./publishers/http-resource-publisher'))({
457
+ resource: userResource,
458
+ name: 'users'
459
+ });
460
+
461
+ // Routes: /api/users/* handled by resourcePublisher
462
+ ```
463
+
464
+ ## Integration with Frontend
465
+
466
+ ### Fetch API Integration
467
+
468
+ ```javascript
469
+ // Frontend JavaScript
470
+ class ApiClient {
471
+ constructor(baseUrl = '') {
472
+ this.baseUrl = baseUrl;
473
+ }
474
+
475
+ async request(endpoint, options = {}) {
476
+ const url = `${this.baseUrl}/api/${endpoint}`;
477
+ const config = {
478
+ headers: {
479
+ 'Content-Type': 'application/json',
480
+ ...options.headers
481
+ },
482
+ ...options
483
+ };
484
+
485
+ if (options.body && typeof options.body === 'object') {
486
+ config.body = JSON.stringify(options.body);
487
+ }
488
+
489
+ const response = await fetch(url, config);
490
+
491
+ if (!response.ok) {
492
+ const error = await response.json();
493
+ throw new Error(error.error || 'API request failed');
494
+ }
495
+
496
+ return response.json();
497
+ }
498
+
499
+ // Convenience methods
500
+ get(endpoint, params) {
501
+ const query = params ? '?' + new URLSearchParams(params) : '';
502
+ return this.request(endpoint + query);
503
+ }
504
+
505
+ post(endpoint, data) {
506
+ return this.request(endpoint, {
507
+ method: 'POST',
508
+ body: data
509
+ });
510
+ }
511
+
512
+ put(endpoint, data) {
513
+ return this.request(endpoint, {
514
+ method: 'PUT',
515
+ body: data
516
+ });
517
+ }
518
+
519
+ delete(endpoint) {
520
+ return this.request(endpoint, {
521
+ method: 'DELETE'
522
+ });
523
+ }
524
+ }
525
+
526
+ // Usage
527
+ const api = new ApiClient();
528
+
529
+ // GET requests
530
+ const users = await api.get('users');
531
+ const user = await api.get('user', { id: 1 });
532
+
533
+ // POST requests
534
+ const newUser = await api.post('create-user', {
535
+ name: 'Charlie',
536
+ email: 'charlie@example.com'
537
+ });
538
+
539
+ // Error handling
540
+ try {
541
+ const result = await api.post('validate', { email: 'invalid' });
542
+ } catch (error) {
543
+ console.error('Validation failed:', error.message);
544
+ }
545
+ ```
546
+
547
+ ## Performance Considerations
548
+
549
+ ### Caching Strategies
550
+
551
+ ```javascript
552
+ api: {
553
+ // Cacheable data
554
+ 'static-config': () => ({
555
+ version: '1.0.0',
556
+ features: ['auth', 'api', 'files'],
557
+ limits: { maxUploadSize: '10MB' }
558
+ }),
559
+
560
+ // Dynamic data with cache headers
561
+ 'stats': () => {
562
+ // Set cache headers in response
563
+ const stats = {
564
+ users: getUserCount(),
565
+ uptime: process.uptime(),
566
+ timestamp: new Date()
567
+ };
568
+
569
+ // Note: Cache headers would be set by middleware
570
+ return stats;
571
+ }
572
+ }
573
+ ```
574
+
575
+ ### Rate Limiting
576
+
577
+ ```javascript
578
+ // Basic rate limiting (implement proper middleware for production)
579
+ let requestCounts = new Map();
580
+
581
+ api: {
582
+ 'rate-limited-endpoint': (data, req) => {
583
+ const clientIP = req.connection.remoteAddress;
584
+ const now = Date.now();
585
+ const windowStart = now - 60000; // 1 minute window
586
+
587
+ // Clean old entries
588
+ for (const [ip, timestamps] of requestCounts) {
589
+ requestCounts.set(ip, timestamps.filter(t => t > windowStart));
590
+ }
591
+
592
+ // Check rate limit
593
+ const timestamps = requestCounts.get(clientIP) || [];
594
+ if (timestamps.length >= 10) { // 10 requests per minute
595
+ throw new Error('Rate limit exceeded');
596
+ }
597
+
598
+ // Record request
599
+ timestamps.push(now);
600
+ requestCounts.set(clientIP, timestamps);
601
+
602
+ return { success: true, data: 'Processed' };
603
+ }
604
+ }
605
+ ```
606
+
607
+ ## Testing Function Publishers
608
+
609
+ ### Unit Testing
610
+
611
+ ```javascript
612
+ const assert = require('assert');
613
+
614
+ // Test function directly
615
+ const helloFunction = (name) => `Hello ${name || 'World'}!`;
616
+
617
+ assert.equal(helloFunction(), 'Hello World!');
618
+ assert.equal(helloFunction('Alice'), 'Hello Alice!');
619
+
620
+ // Test with simulated HTTP
621
+ const Function_Publisher = require('./publishers/http-function-publisher');
622
+
623
+ function testFunctionPublisher() {
624
+ const publisher = new Function_Publisher(helloFunction);
625
+
626
+ // Mock request/response
627
+ const mockReq = {
628
+ headers: { 'content-type': 'application/json' },
629
+ on: function(event, callback) {
630
+ if (event === 'data') callback(Buffer.from('{"name":"Test"}'));
631
+ if (event === 'end') callback();
632
+ }
633
+ };
634
+
635
+ let responseData = '';
636
+ const mockRes = {
637
+ writeHead: () => {},
638
+ end: (data) => { responseData = data; }
639
+ };
640
+
641
+ publisher.handle_http(mockReq, mockRes);
642
+
643
+ // Verify response
644
+ const response = JSON.parse(responseData);
645
+ assert.equal(response.result, 'Hello Test!');
646
+ }
647
+ ```
648
+
649
+ ### Integration Testing
650
+
651
+ ```javascript
652
+ const http = require('http');
653
+
654
+ function testAPIEndpoint() {
655
+ return new Promise((resolve, reject) => {
656
+ const req = http.request({
657
+ hostname: 'localhost',
658
+ port: 3000,
659
+ path: '/api/hello',
660
+ method: 'POST',
661
+ headers: {
662
+ 'Content-Type': 'application/json'
663
+ }
664
+ }, (res) => {
665
+ let data = '';
666
+ res.on('data', chunk => data += chunk);
667
+ res.on('end', () => {
668
+ try {
669
+ const response = JSON.parse(data);
670
+ resolve(response);
671
+ } catch (err) {
672
+ reject(err);
673
+ }
674
+ });
675
+ });
676
+
677
+ req.write(JSON.stringify({ name: 'Integration Test' }));
678
+ req.end();
679
+ });
680
+ }
681
+
682
+ // Usage
683
+ testAPIEndpoint().then(result => {
684
+ console.log('Integration test passed:', result);
685
+ }).catch(err => {
686
+ console.error('Integration test failed:', err);
687
+ });
688
+ ```
689
+
690
+ ## Best Practices
691
+
692
+ ### API Design
693
+
694
+ 1. **Consistent Naming**: Use lowercase, hyphen-separated endpoint names
695
+ 2. **RESTful Patterns**: Use appropriate HTTP methods (GET, POST, PUT, DELETE)
696
+ 3. **Versioning**: Consider API versioning for breaking changes
697
+ 4. **Documentation**: Document all endpoints with expected inputs/outputs
698
+ 5. **Error Handling**: Provide meaningful error messages
699
+
700
+ ### Security
701
+
702
+ 1. **Input Validation**: Always validate and sanitize inputs
703
+ 2. **Authentication**: Implement proper auth for sensitive endpoints
704
+ 3. **Rate Limiting**: Prevent abuse with rate limiting
705
+ 4. **CORS**: Configure appropriate CORS policies
706
+ 5. **HTTPS**: Use HTTPS in production
707
+
708
+ ### Performance
709
+
710
+ 1. **Caching**: Implement appropriate caching strategies
711
+ 2. **Compression**: Enable gzip compression for responses
712
+ 3. **Async Operations**: Use async/await for I/O operations
713
+ 4. **Connection Pooling**: Use connection pools for databases
714
+ 5. **Monitoring**: Monitor response times and error rates
715
+
716
+ ## Troubleshooting
717
+
718
+ ### Common Issues
719
+
720
+ #### Content-Type Mismatch
721
+ ```
722
+ Error: Unexpected token in JSON
723
+ ```
724
+ **Cause:** Sending wrong content-type header
725
+ **Fix:** Ensure `Content-Type: application/json` for JSON data
726
+
727
+ #### Function Not Found
728
+ ```
729
+ Error: Route not found
730
+ ```
731
+ **Cause:** API endpoint not properly registered
732
+ **Fix:** Check that function is in the `api` object and server restarted
733
+
734
+ #### Async Function Issues
735
+ ```
736
+ Error: Function did not return a value
737
+ ```
738
+ **Cause:** Async function not properly awaited
739
+ **Fix:** Ensure async functions use `async/await` pattern
740
+
741
+ #### CORS Issues
742
+ ```
743
+ Error: CORS policy blocked
744
+ ```
745
+ **Cause:** Missing CORS headers
746
+ **Fix:** Add CORS middleware or headers
747
+
748
+ ## Migration from Other Frameworks
749
+
750
+ ### From Express.js
751
+
752
+ ```javascript
753
+ // Express.js
754
+ app.get('/api/users', (req, res) => {
755
+ res.json(getUsers());
756
+ });
757
+
758
+ // JSGUI3 Server
759
+ Server.serve({
760
+ api: {
761
+ 'users': () => getUsers()
762
+ }
763
+ });
764
+ ```
765
+
766
+ ### From RESTify
767
+
768
+ ```javascript
769
+ // RESTify
770
+ server.get('/api/users/:id', (req, res) => {
771
+ res.send(getUser(req.params.id));
772
+ });
773
+
774
+ // JSGUI3 Server
775
+ Server.serve({
776
+ api: {
777
+ 'user': ({ id }) => getUser(id)
778
+ }
779
+ });
780
+ ```
781
+
782
+ ## Advanced Topics
783
+
784
+ ### Custom Publishers
785
+
786
+ ```javascript
787
+ const HTTP_Publisher = require('./publishers/http-publisher');
788
+
789
+ class CustomPublisher extends HTTP_Publisher {
790
+ constructor(spec) {
791
+ super(spec);
792
+ this.customLogic = spec.customLogic;
793
+ }
794
+
795
+ handle_http(req, res) {
796
+ // Custom request handling logic
797
+ if (this.customLogic(req)) {
798
+ // Handle custom case
799
+ res.writeHead(200, { 'Content-Type': 'application/json' });
800
+ res.end(JSON.stringify({ custom: true }));
801
+ } else {
802
+ // Fall back to default
803
+ super.handle_http(req, res);
804
+ }
805
+ }
806
+ }
807
+ ```
808
+
809
+ ### Middleware Integration
810
+
811
+ ```javascript
812
+ // Custom middleware
813
+ function loggingMiddleware(req, res, next) {
814
+ console.log(`${req.method} ${req.url}`);
815
+ next();
816
+ }
817
+
818
+ function authMiddleware(req, res, next) {
819
+ const token = req.headers.authorization;
820
+ if (!token) {
821
+ res.writeHead(401);
822
+ res.end('Unauthorized');
823
+ return;
824
+ }
825
+ // Validate token...
826
+ next();
827
+ }
828
+
829
+ Server.serve({
830
+ ctrl: MyControl,
831
+ middleware: [loggingMiddleware, authMiddleware],
832
+ api: { /* ... */ }
833
+ });
834
+ ```
835
+
836
+ ## Conclusion
837
+
838
+ Function publishers provide a powerful, easy-to-use way to create JSON APIs with JSGUI3 Server. The automatic content-type handling, promise support, and flexible input/output processing make it simple to build robust backend services.
839
+
840
+ Key benefits:
841
+ - **Automatic JSON handling** - No manual serialization
842
+ - **Promise/async support** - Modern JavaScript patterns
843
+ - **Flexible inputs** - JSON, text, or no body
844
+ - **Error propagation** - Automatic error handling
845
+ - **RESTful routing** - Automatic `/api/` prefixing
846
+
847
+ For complex applications, consider combining function publishers with resource publishers for full CRUD operations and more sophisticated API patterns.