@misterzik/espressojs 3.2.6 → 3.3.1

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.
@@ -0,0 +1,451 @@
1
+ # Multiple API Endpoints Guide
2
+
3
+ EspressoJS supports configuring and using multiple API endpoints simultaneously. This guide shows you how to set up and use multiple APIs in your application.
4
+
5
+ ## 📋 Configuration
6
+
7
+ ### Basic Setup
8
+
9
+ In your `config.json`, you can define multiple API endpoints using the pattern `api`, `api2`, `api3`, etc.:
10
+
11
+ ```json
12
+ {
13
+ "instance": "production",
14
+ "port": 3001,
15
+ "hostname": "",
16
+ "publicDirectory": "/public",
17
+ "mongoDB": {
18
+ "enabled": false
19
+ },
20
+ "api": {
21
+ "enabled": true,
22
+ "uri": "https://api.example.com/v1/",
23
+ "method": "GET",
24
+ "headers": {
25
+ "Content-Type": "application/json"
26
+ },
27
+ "timeout": 30000,
28
+ "retries": 2
29
+ },
30
+ "api2": {
31
+ "enabled": true,
32
+ "uri": "https://api.example.com/v1/news",
33
+ "method": "GET",
34
+ "headers": {
35
+ "Content-Type": "application/json",
36
+ "Authorization": "Bearer YOUR_TOKEN"
37
+ },
38
+ "timeout": 15000,
39
+ "retries": 1
40
+ },
41
+ "api3": {
42
+ "enabled": true,
43
+ "uri": "https://api.example.com/api",
44
+ "method": "POST",
45
+ "headers": {
46
+ "Content-Type": "application/json",
47
+ "X-Custom-Header": "value"
48
+ }
49
+ }
50
+ }
51
+ ```
52
+
53
+ ### Configuration Options
54
+
55
+ Each API endpoint supports the following options:
56
+
57
+ | Option | Type | Required | Default | Description |
58
+ |--------|------|----------|---------|-------------|
59
+ | `enabled` | boolean | No | `true` | Enable/disable this API endpoint |
60
+ | `uri` | string | Yes | `""` | Base URL for the API |
61
+ | `method` | string | No | `"GET"` | Default HTTP method (GET, POST, PUT, DELETE, PATCH, HEAD, OPTIONS) |
62
+ | `headers` | object | No | `{"Content-Type": "application/json"}` | Default headers for requests |
63
+ | `timeout` | number | No | `30000` | Request timeout in milliseconds |
64
+ | `retries` | number | No | `0` | Number of retry attempts on failure (0-5) |
65
+
66
+ ## 🚀 Usage
67
+
68
+ ### Method 1: Using the API Manager
69
+
70
+ The API Manager is automatically initialized and available in your routes:
71
+
72
+ ```javascript
73
+ const { apiManager } = require('../index');
74
+
75
+ // Make a request to a specific API
76
+ router.get('/data', async (req, res) => {
77
+ const data = await apiManager.request('api2', '/endpoint');
78
+ res.json(data);
79
+ });
80
+ ```
81
+
82
+ ### Method 2: Multiple Parallel Requests
83
+
84
+ Fetch data from multiple APIs simultaneously:
85
+
86
+ ```javascript
87
+ router.get('/combined', async (req, res) => {
88
+ const [data1, data2, data3] = await Promise.all([
89
+ apiManager.request('api', '/users'),
90
+ apiManager.request('api2', '/news'),
91
+ apiManager.request('api3', '/stats')
92
+ ]);
93
+
94
+ res.json({ data1, data2, data3 });
95
+ });
96
+ ```
97
+
98
+ ### Method 3: Custom Request Options
99
+
100
+ Override default configuration per request:
101
+
102
+ ```javascript
103
+ router.post('/custom', async (req, res) => {
104
+ const data = await apiManager.request('api', '/endpoint', {
105
+ method: 'POST',
106
+ data: req.body,
107
+ headers: {
108
+ 'Custom-Header': 'value'
109
+ },
110
+ timeout: 5000,
111
+ retries: 3
112
+ });
113
+
114
+ res.json(data);
115
+ });
116
+ ```
117
+
118
+ ### Method 4: Create Axios Instance
119
+
120
+ For more control, create a custom Axios instance:
121
+
122
+ ```javascript
123
+ router.get('/advanced', async (req, res) => {
124
+ const client = apiManager.createAxiosInstance('api2');
125
+
126
+ // Use like regular axios
127
+ const response = await client.get('/endpoint', {
128
+ params: { page: 1, limit: 10 }
129
+ });
130
+
131
+ res.json(response.data);
132
+ });
133
+ ```
134
+
135
+ ## 🔍 API Manager Methods
136
+
137
+ ### `request(apiName, endpoint, options)`
138
+
139
+ Make a request to a configured API endpoint.
140
+
141
+ **Parameters:**
142
+ - `apiName` (string): Name of the API (e.g., 'api', 'api2', 'api3')
143
+ - `endpoint` (string): Endpoint path to append to base URI
144
+ - `options` (object): Axios request options (optional)
145
+
146
+ **Returns:** Promise with response data
147
+
148
+ **Example:**
149
+ ```javascript
150
+ const data = await apiManager.request('api2', '/users/123', {
151
+ method: 'GET',
152
+ headers: { 'X-Custom': 'value' }
153
+ });
154
+ ```
155
+
156
+ ### `getAPI(name)`
157
+
158
+ Get configuration for a specific API.
159
+
160
+ **Parameters:**
161
+ - `name` (string): API name (defaults to 'api')
162
+
163
+ **Returns:** API configuration object
164
+
165
+ **Example:**
166
+ ```javascript
167
+ const apiConfig = apiManager.getAPI('api2');
168
+ console.log(apiConfig.baseURL); // https://api.example.com/v1/news
169
+ ```
170
+
171
+ ### `getAllAPIs()`
172
+
173
+ Get all configured API endpoints.
174
+
175
+ **Returns:** Object with all API configurations
176
+
177
+ **Example:**
178
+ ```javascript
179
+ const allAPIs = apiManager.getAllAPIs();
180
+ console.log(Object.keys(allAPIs)); // ['api', 'api2', 'api3']
181
+ ```
182
+
183
+ ### `hasAPI(name)`
184
+
185
+ Check if an API is configured.
186
+
187
+ **Parameters:**
188
+ - `name` (string): API name to check
189
+
190
+ **Returns:** Boolean
191
+
192
+ **Example:**
193
+ ```javascript
194
+ if (apiManager.hasAPI('api2')) {
195
+ // Use api2
196
+ }
197
+ ```
198
+
199
+ ### `createAxiosInstance(apiName)`
200
+
201
+ Create a custom Axios instance for an API.
202
+
203
+ **Parameters:**
204
+ - `apiName` (string): Name of the API
205
+
206
+ **Returns:** Axios instance
207
+
208
+ **Example:**
209
+ ```javascript
210
+ const client = apiManager.createAxiosInstance('api3');
211
+ const response = await client.post('/data', { key: 'value' });
212
+ ```
213
+
214
+ ## 💡 Common Patterns
215
+
216
+ ### Fallback Pattern
217
+
218
+ Try primary API, fallback to secondary:
219
+
220
+ ```javascript
221
+ router.get('/data', async (req, res) => {
222
+ let data;
223
+
224
+ try {
225
+ data = await apiManager.request('api', '/data');
226
+ } catch (error) {
227
+ // Fallback to api2
228
+ data = await apiManager.request('api2', '/data');
229
+ }
230
+
231
+ res.json(data);
232
+ });
233
+ ```
234
+
235
+ ### Conditional API Usage
236
+
237
+ Use different APIs based on conditions:
238
+
239
+ ```javascript
240
+ router.get('/data/:type', async (req, res) => {
241
+ const { type } = req.params;
242
+
243
+ let apiName = 'api';
244
+ if (type === 'news') apiName = 'api2';
245
+ if (type === 'stats') apiName = 'api3';
246
+
247
+ const data = await apiManager.request(apiName, '/data');
248
+ res.json(data);
249
+ });
250
+ ```
251
+
252
+ ### Error Handling with Retries
253
+
254
+ The API Manager automatically retries failed requests based on the `retries` configuration:
255
+
256
+ ```javascript
257
+ // This will retry up to 2 times with exponential backoff
258
+ const data = await apiManager.request('api', '/endpoint', {
259
+ retries: 2
260
+ });
261
+ ```
262
+
263
+ ### Proxy Pattern
264
+
265
+ Create a proxy endpoint for any configured API:
266
+
267
+ ```javascript
268
+ router.all('/proxy/:apiName/*', async (req, res) => {
269
+ const { apiName } = req.params;
270
+ const endpoint = req.params[0];
271
+
272
+ if (!apiManager.hasAPI(apiName)) {
273
+ return res.status(404).json({ error: 'API not found' });
274
+ }
275
+
276
+ const data = await apiManager.request(apiName, `/${endpoint}`, {
277
+ method: req.method,
278
+ data: req.body,
279
+ params: req.query
280
+ });
281
+
282
+ res.json(data);
283
+ });
284
+ ```
285
+
286
+ ## 🔒 Security Best Practices
287
+
288
+ ### 1. Use Environment Variables for Tokens
289
+
290
+ Store sensitive data in `.env`:
291
+
292
+ ```env
293
+ API_TOKEN=your_secret_token
294
+ API2_KEY=another_secret_key
295
+ ```
296
+
297
+ Reference in `config.json`:
298
+
299
+ ```json
300
+ {
301
+ "api2": {
302
+ "headers": {
303
+ "Authorization": "Bearer ${API_TOKEN}"
304
+ }
305
+ }
306
+ }
307
+ ```
308
+
309
+ Or set headers dynamically in your code:
310
+
311
+ ```javascript
312
+ const data = await apiManager.request('api2', '/endpoint', {
313
+ headers: {
314
+ 'Authorization': `Bearer ${process.env.API_TOKEN}`
315
+ }
316
+ });
317
+ ```
318
+
319
+ ### 2. Set Appropriate Timeouts
320
+
321
+ Configure timeouts to prevent hanging requests:
322
+
323
+ ```json
324
+ {
325
+ "api": {
326
+ "timeout": 5000
327
+ }
328
+ }
329
+ ```
330
+
331
+ ### 3. Limit Retries
332
+
333
+ Set reasonable retry limits to avoid overwhelming APIs:
334
+
335
+ ```json
336
+ {
337
+ "api": {
338
+ "retries": 2
339
+ }
340
+ }
341
+ ```
342
+
343
+ ## 📊 Monitoring
344
+
345
+ ### Log API Requests
346
+
347
+ The API Manager automatically logs all requests:
348
+
349
+ ```
350
+ [info]: API endpoint 'api2' loaded: https://api.example.com/v1/news
351
+ [debug]: API request to api2: GET https://api.example.com/v1/news/latest (attempt 1/1)
352
+ [info]: API api2 request successful: 200
353
+ ```
354
+
355
+ ### Track API Health
356
+
357
+ Create a health check endpoint:
358
+
359
+ ```javascript
360
+ router.get('/api-health', async (req, res) => {
361
+ const apis = apiManager.getAllAPIs();
362
+ const health = {};
363
+
364
+ for (const [name, config] of Object.entries(apis)) {
365
+ try {
366
+ await apiManager.request(name, '/health', { timeout: 5000 });
367
+ health[name] = 'healthy';
368
+ } catch (error) {
369
+ health[name] = 'unhealthy';
370
+ }
371
+ }
372
+
373
+ res.json({ status: 'ok', apis: health });
374
+ });
375
+ ```
376
+
377
+ ## 🎯 Real-World Example
378
+
379
+ Here's a complete example using the client's production configuration:
380
+
381
+ ```javascript
382
+ const express = require('express');
383
+ const router = express.Router();
384
+ const { apiManager } = require('../index');
385
+ const { asyncHandler } = require('../server/middleware/errorHandler');
386
+
387
+ // Get exchange data from primary API
388
+ router.get('/exchange', asyncHandler(async (req, res) => {
389
+ const data = await apiManager.request('api', '');
390
+ res.json(data);
391
+ }));
392
+
393
+ // Get news from api2
394
+ router.get('/news', asyncHandler(async (req, res) => {
395
+ const news = await apiManager.request('api2', '');
396
+ res.json(news);
397
+ }));
398
+
399
+ // Get general API data from api3
400
+ router.get('/general', asyncHandler(async (req, res) => {
401
+ const data = await apiManager.request('api3', '');
402
+ res.json(data);
403
+ }));
404
+
405
+ // Combined dashboard data
406
+ router.get('/dashboard', asyncHandler(async (req, res) => {
407
+ const [exchange, news, general] = await Promise.allSettled([
408
+ apiManager.request('api', ''),
409
+ apiManager.request('api2', ''),
410
+ apiManager.request('api3', '')
411
+ ]);
412
+
413
+ res.json({
414
+ exchange: exchange.status === 'fulfilled' ? exchange.value : null,
415
+ news: news.status === 'fulfilled' ? news.value : null,
416
+ general: general.status === 'fulfilled' ? general.value : null
417
+ });
418
+ }));
419
+
420
+ module.exports = router;
421
+ ```
422
+
423
+ ## 🆘 Troubleshooting
424
+
425
+ ### API not found error
426
+
427
+ **Error:** `API 'api2' not found in configuration`
428
+
429
+ **Solution:** Ensure the API is defined in `config.json` and `enabled` is not set to `false`.
430
+
431
+ ### Timeout errors
432
+
433
+ **Error:** Request timeout
434
+
435
+ **Solution:** Increase the `timeout` value in your API configuration or request options.
436
+
437
+ ### Validation errors
438
+
439
+ **Error:** Configuration validation failed
440
+
441
+ **Solution:** Run `node cli validate` to check your configuration for errors.
442
+
443
+ ## 📚 See Also
444
+
445
+ - [Basic API Example](../examples/basic-api.js)
446
+ - [Multiple APIs Example](../examples/multiple-apis.js)
447
+ - [Configuration Guide](../README.md#configuration)
448
+
449
+ ---
450
+
451
+ **Need help?** Open an issue on [GitHub](https://github.com/misterzik/Espresso.js/issues)
@@ -0,0 +1,89 @@
1
+ # EspressoJS Examples
2
+
3
+ This directory contains example implementations to help you get started with EspressoJS.
4
+
5
+ ## 📁 Available Examples
6
+
7
+ ### `basic-api.js`
8
+ Demonstrates how to create RESTful API routes with:
9
+ - GET, POST, PUT, DELETE operations
10
+ - Request validation using express-validator
11
+ - Error handling with asyncHandler
12
+ - Proper response formatting
13
+
14
+ **Usage:**
15
+ ```javascript
16
+ // In your routes/api.js
17
+ module.exports = require('./examples/basic-api');
18
+ ```
19
+
20
+ ### `mongodb-example.js`
21
+ Shows MongoDB integration with Mongoose:
22
+ - Schema definition and validation
23
+ - CRUD operations
24
+ - Pagination
25
+ - Search functionality
26
+ - Error handling
27
+
28
+ **Usage:**
29
+ ```javascript
30
+ // In your routes/db.js
31
+ module.exports = require('./examples/mongodb-example');
32
+ ```
33
+
34
+ ### `multiple-apis.js` ⭐ NEW
35
+ Demonstrates using multiple API endpoints:
36
+ - Making requests to different APIs (api, api2, api3)
37
+ - Parallel API requests
38
+ - Custom request options
39
+ - Creating Axios instances
40
+ - Conditional API usage and fallbacks
41
+ - API proxy patterns
42
+ - Error handling with retries
43
+
44
+ **Usage:**
45
+ ```javascript
46
+ // In your routes/api.js
47
+ module.exports = require('./examples/multiple-apis');
48
+ ```
49
+
50
+ **Configuration:**
51
+ ```json
52
+ {
53
+ "api": {
54
+ "enabled": true,
55
+ "uri": "https://api.example.com/v1/"
56
+ },
57
+ "api2": {
58
+ "uri": "https://api.example.com/v1/news"
59
+ },
60
+ "api3": {
61
+ "uri": "https://api.example.com/api"
62
+ }
63
+ }
64
+ ```
65
+
66
+ ## 🚀 Getting Started
67
+
68
+ 1. Copy the example file you want to use
69
+ 2. Place it in your `routes/` directory
70
+ 3. Customize it for your needs
71
+ 4. Enable the routes in your `config.json`
72
+
73
+ ## 💡 Tips
74
+
75
+ - Use `asyncHandler` for all async route handlers
76
+ - Validate input with express-validator
77
+ - Return consistent response formats
78
+ - Use proper HTTP status codes
79
+ - Handle errors gracefully
80
+
81
+ ## 📚 Learn More
82
+
83
+ - [Express.js Documentation](https://expressjs.com/)
84
+ - [Mongoose Documentation](https://mongoosejs.com/)
85
+ - [Express Validator](https://express-validator.github.io/)
86
+
87
+ ## 🤝 Contributing
88
+
89
+ Have a useful example? Submit a PR to share it with the community!
@@ -0,0 +1,116 @@
1
+ /*
2
+ * EspressoJS - Example API Routes
3
+ * This file demonstrates how to create custom API routes
4
+ */
5
+
6
+ const express = require('express');
7
+ const router = express.Router();
8
+ const { body, validationResult } = require('express-validator');
9
+ const { asyncHandler, AppError } = require('../server/middleware/errorHandler');
10
+
11
+ // Example: GET all items
12
+ router.get('/items', asyncHandler(async (req, res) => {
13
+ const items = [
14
+ { id: 1, name: 'Item 1', description: 'First item' },
15
+ { id: 2, name: 'Item 2', description: 'Second item' },
16
+ ];
17
+
18
+ res.status(200).json({
19
+ status: 'success',
20
+ results: items.length,
21
+ data: { items }
22
+ });
23
+ }));
24
+
25
+ // Example: GET single item by ID
26
+ router.get('/items/:id', asyncHandler(async (req, res) => {
27
+ const { id } = req.params;
28
+
29
+ // Simulate database lookup
30
+ const item = { id, name: `Item ${id}`, description: 'Example item' };
31
+
32
+ if (!item) {
33
+ throw new AppError('Item not found', 404);
34
+ }
35
+
36
+ res.status(200).json({
37
+ status: 'success',
38
+ data: { item }
39
+ });
40
+ }));
41
+
42
+ // Example: POST create new item with validation
43
+ router.post('/items',
44
+ [
45
+ body('name').notEmpty().withMessage('Name is required'),
46
+ body('description').optional().isLength({ max: 500 })
47
+ ],
48
+ asyncHandler(async (req, res) => {
49
+ const errors = validationResult(req);
50
+
51
+ if (!errors.isEmpty()) {
52
+ return res.status(400).json({
53
+ status: 'fail',
54
+ errors: errors.array()
55
+ });
56
+ }
57
+
58
+ const { name, description } = req.body;
59
+
60
+ // Simulate database insert
61
+ const newItem = {
62
+ id: Date.now(),
63
+ name,
64
+ description,
65
+ createdAt: new Date().toISOString()
66
+ };
67
+
68
+ res.status(201).json({
69
+ status: 'success',
70
+ data: { item: newItem }
71
+ });
72
+ })
73
+ );
74
+
75
+ // Example: PUT update item
76
+ router.put('/items/:id',
77
+ [
78
+ body('name').optional().notEmpty(),
79
+ body('description').optional().isLength({ max: 500 })
80
+ ],
81
+ asyncHandler(async (req, res) => {
82
+ const errors = validationResult(req);
83
+
84
+ if (!errors.isEmpty()) {
85
+ return res.status(400).json({
86
+ status: 'fail',
87
+ errors: errors.array()
88
+ });
89
+ }
90
+
91
+ const { id } = req.params;
92
+ const updates = req.body;
93
+
94
+ // Simulate database update
95
+ const updatedItem = {
96
+ id,
97
+ ...updates,
98
+ updatedAt: new Date().toISOString()
99
+ };
100
+
101
+ res.status(200).json({
102
+ status: 'success',
103
+ data: { item: updatedItem }
104
+ });
105
+ })
106
+ );
107
+
108
+ // Example: DELETE item
109
+ router.delete('/items/:id', asyncHandler(async (req, res) => {
110
+ const { id } = req.params;
111
+
112
+ // Simulate database delete
113
+ res.status(204).send();
114
+ }));
115
+
116
+ module.exports = router;