dynamic-api-builder-js 1.0.0 → 1.0.2

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.
package/Readme.md ADDED
@@ -0,0 +1,541 @@
1
+ # dynamic-api-builder-js
2
+
3
+ > **Configuration-driven REST API generator for Node.js** — define your endpoints in JSON, get a fully working Express API instantly.
4
+
5
+ [![npm version](https://img.shields.io/badge/npm-1.0.0-blue)](https://www.npmjs.com/package/dynamic-api-builder-js)
6
+ [![license](https://img.shields.io/badge/license-ISC-green)](LICENSE)
7
+ [![node](https://img.shields.io/badge/node-%3E%3D20-brightgreen)](https://nodejs.org)
8
+
9
+ ---
10
+
11
+ ## Table of Contents
12
+
13
+ - [Overview](#overview)
14
+ - [Installation](#installation)
15
+ - [Quick Start](#quick-start)
16
+ - [Configuration](#configuration)
17
+ - [Database Config](#database-config)
18
+ - [API Config](#api-config)
19
+ - [API Types](#api-types)
20
+ - [CRUD](#crud)
21
+ - [TRANSACTION](#transaction)
22
+ - [CALL\_FUNCTION](#call_function)
23
+ - [CALL\_PROCEDURE](#call_procedure)
24
+ - [FUNCTION](#function)
25
+ - [Hooks](#hooks)
26
+ - [Validation](#validation)
27
+ - [Filters & Pagination](#filters--pagination)
28
+ - [Joins](#joins)
29
+ - [Response Format](#response-format)
30
+ - [Advanced Usage](#advanced-usage)
31
+ - [API Reference](#api-reference)
32
+
33
+ ---
34
+
35
+ ## Overview
36
+
37
+ `dynamic-api-builder-js` (DAB) eliminates the boilerplate of writing Express routes, SQL queries, and request validation by hand. You declare your API endpoints as a JSON config, and DAB registers them on an Express router automatically — including CRUD operations, multi-step transactions, database function/procedure calls, and fully custom handlers.
38
+
39
+ **Supports MySQL and PostgreSQL.**
40
+
41
+ ---
42
+
43
+ ## Installation
44
+
45
+ ```bash
46
+ npm install dynamic-api-builder-js
47
+ ```
48
+
49
+ **Peer dependencies** (install separately):
50
+
51
+ ```bash
52
+ # For MySQL
53
+ npm install mysql2
54
+
55
+ # For PostgreSQL
56
+ npm install pg
57
+ ```
58
+
59
+ ---
60
+
61
+ ## Quick Start
62
+
63
+ ```js
64
+ const express = require('express');
65
+ const dabApi = require('dynamic-api-builder-js');
66
+
67
+ const app = express();
68
+ app.use(express.json());
69
+
70
+ const { router } = dabApi({
71
+ database: {
72
+ type: 'mysql', // 'mysql' | 'postgres'
73
+ host: 'localhost',
74
+ port: 3306,
75
+ user: 'root',
76
+ password: 'secret',
77
+ database: 'mydb',
78
+ },
79
+ apis: [
80
+ {
81
+ id: 'list-users',
82
+ endpoint: '/users',
83
+ method: 'GET',
84
+ type: 'CRUD',
85
+ operation: 'READ',
86
+ table: 'users',
87
+ columns: ['id', 'name', 'email'],
88
+ pagination: true,
89
+ },
90
+ {
91
+ id: 'create-user',
92
+ endpoint: '/users',
93
+ method: 'POST',
94
+ type: 'CRUD',
95
+ operation: 'CREATE',
96
+ table: 'users',
97
+ columns: ['name', 'email', 'password'],
98
+ },
99
+ ],
100
+ });
101
+
102
+ app.use('/api', router);
103
+ app.listen(3000, () => console.log('Server running on port 3000'));
104
+ ```
105
+
106
+ ---
107
+
108
+ ## Configuration
109
+
110
+ ### Database Config
111
+
112
+ Pass a `database` object at the top level of your config. DAB creates and manages the connection pool for you.
113
+
114
+ | Field | Type | Default | Description |
115
+ |-------------------|----------|---------------|------------------------------------|
116
+ | `type` | `string` | `"mysql"` | `"mysql"` or `"postgres"` |
117
+ | `host` | `string` | `"localhost"` | Database host |
118
+ | `port` | `number` | `3306` | Database port |
119
+ | `user` | `string` | `"root"` | Database user |
120
+ | `password` | `string` | `""` | Database password |
121
+ | `database` | `string` | `""` | Database/schema name |
122
+ | `connectionLimit` | `number` | `10` | Max connections in the pool |
123
+
124
+ ### API Config
125
+
126
+ Each entry in the `apis` array describes a single route.
127
+
128
+ | Field | Type | Required | Description |
129
+ |--------------|----------|----------|----------------------------------------------------------|
130
+ | `id` | `string` | No | Identifier used in logs and warnings |
131
+ | `endpoint` | `string` | Yes | Express route path (e.g. `/users/:id`) |
132
+ | `method` | `string` | Yes | HTTP method: `GET`, `POST`, `PUT`, `DELETE`, etc. |
133
+ | `type` | `string` | Yes | API type (see [API Types](#api-types)) |
134
+ | `validation` | `object` | No | Validation rules (see [Validation](#validation)) |
135
+ | `hooks` | `object` | No | `before` / `after` hook names (see [Hooks](#hooks)) |
136
+
137
+ ---
138
+
139
+ ## API Types
140
+
141
+ ### CRUD
142
+
143
+ Handles standard Create, Read, Update, Delete operations against a single table.
144
+
145
+ ```js
146
+ {
147
+ id: 'get-user',
148
+ endpoint: '/users/:id',
149
+ method: 'GET',
150
+ type: 'CRUD',
151
+ operation: 'READ', // 'CREATE' | 'READ' | 'UPDATE' | 'DELETE'
152
+ table: 'users',
153
+ columns: ['id', 'name', 'email'],
154
+ filters: ['status', 'role'], // query params used as WHERE filters
155
+ pagination: true, // enables ?page=&limit= query params
156
+ joins: [ // optional JOIN clauses
157
+ {
158
+ type: 'LEFT', // 'INNER' | 'LEFT' | 'RIGHT'
159
+ table: 'roles',
160
+ condition: 'users.role_id = roles.id'
161
+ }
162
+ ],
163
+ filterConfig: {
164
+ name: { operator: 'LIKE' }, // override filter operator
165
+ orFields: ['name', 'email'] // fields matched by ?_or= query param
166
+ }
167
+ }
168
+ ```
169
+
170
+ **Operations:**
171
+
172
+ | Operation | HTTP Method | Description |
173
+ |------------|-------------|----------------------------------|
174
+ | `READ` | `GET` | Fetch rows; supports filter/pagination |
175
+ | `CREATE` | `POST` | Insert a new row |
176
+ | `UPDATE` | `PUT/PATCH` | Update row by `:id` |
177
+ | `DELETE` | `DELETE` | Delete row by `:id` |
178
+
179
+ ---
180
+
181
+ ### TRANSACTION
182
+
183
+ Executes multiple database steps as an atomic transaction. Steps run in order; each step's result is passed to the next via `map`.
184
+
185
+ ```js
186
+ {
187
+ id: 'transfer-funds',
188
+ endpoint: '/transfer',
189
+ method: 'POST',
190
+ type: 'TRANSACTION',
191
+ steps: [
192
+ {
193
+ operation: 'CREATE',
194
+ table: 'ledger',
195
+ columns: ['account_id', 'amount', 'type'],
196
+ },
197
+ {
198
+ operation: 'UPDATE',
199
+ table: 'balances',
200
+ columns: ['balance'],
201
+ map: {
202
+ // Map a value from a previous step's result
203
+ // "$stepResultKey.fieldName"
204
+ balance: '$0.amount'
205
+ }
206
+ }
207
+ ]
208
+ }
209
+ ```
210
+
211
+ A step can also use a custom handler instead of a CRUD operation:
212
+
213
+ ```js
214
+ { handler: 'myCustomHookName' }
215
+ ```
216
+
217
+ ---
218
+
219
+ ### CALL\_FUNCTION
220
+
221
+ Calls a database scalar function and returns its result.
222
+
223
+ ```js
224
+ {
225
+ id: 'get-discount',
226
+ endpoint: '/discount',
227
+ method: 'GET',
228
+ type: 'CALL_FUNCTION',
229
+ function: 'calculate_discount', // DB function name
230
+ params: [
231
+ { name: 'user_id', source: 'query' },
232
+ { name: 'coupon', source: 'body' },
233
+ { name: 'currency', source: 'static', value: 'INR' }
234
+ ]
235
+ }
236
+ ```
237
+
238
+ **Parameter sources:**
239
+
240
+ | Source | Reads from |
241
+ |-----------|-------------------------------|
242
+ | `body` | `req.body[name]` |
243
+ | `query` | `req.query[name]` |
244
+ | `params` | `req.params[name]` |
245
+ | `headers` | `req.headers[name]` |
246
+ | `static` | Hardcoded `value` in config |
247
+
248
+ ---
249
+
250
+ ### CALL\_PROCEDURE
251
+
252
+ Calls a stored procedure. Returns a single result set or an array of result sets when the procedure returns multiple.
253
+
254
+ ```js
255
+ {
256
+ id: 'sync-inventory',
257
+ endpoint: '/inventory/sync',
258
+ method: 'POST',
259
+ type: 'CALL_PROCEDURE',
260
+ procedure: 'sync_inventory_proc',
261
+ params: [
262
+ { name: 'warehouse_id', source: 'body' },
263
+ { name: 'triggered_by', source: 'static', value: 'api' }
264
+ ]
265
+ }
266
+ ```
267
+
268
+ ---
269
+
270
+ ### FUNCTION
271
+
272
+ Executes a fully custom JavaScript handler — useful for complex logic that doesn't fit the other types.
273
+
274
+ ```js
275
+ const { hooks } = dabApi({ ... });
276
+
277
+ hooks.register('myHandler', async (req) => {
278
+ // any custom logic
279
+ return { message: 'done' };
280
+ });
281
+
282
+ // In your API config:
283
+ {
284
+ id: 'custom-endpoint',
285
+ endpoint: '/custom',
286
+ method: 'POST',
287
+ type: 'FUNCTION',
288
+ handler: 'myHandler'
289
+ }
290
+ ```
291
+
292
+ ---
293
+
294
+ ## Hooks
295
+
296
+ Hooks let you run code **before** or **after** the main operation executes — great for password hashing, logging, or enriching response data.
297
+
298
+ ```js
299
+ const { hooks } = dabApi(config);
300
+
301
+ // Register a hook
302
+ hooks.register('hashPassword', async (req) => {
303
+ if (req.body.password) {
304
+ req.body.password = await bcrypt.hash(req.body.password, 10);
305
+ }
306
+ });
307
+
308
+ // Use in API config
309
+ {
310
+ type: 'CRUD',
311
+ operation: 'CREATE',
312
+ table: 'users',
313
+ columns: ['name', 'email', 'password'],
314
+ hooks: {
315
+ before: 'hashPassword', // runs before the DB operation
316
+ after: 'sendWelcomeEmail' // runs after, receives (req, result)
317
+ }
318
+ }
319
+ ```
320
+
321
+ **Built-in hooks** (registered automatically):
322
+
323
+ | Hook Name | Description |
324
+ |------------------|-------------------------------------------------|
325
+ | `hashPassword` | Hashes `req.body.password` using bcrypt before saving |
326
+
327
+ **Hook methods on `DabHooks`:**
328
+
329
+ ```js
330
+ hooks.register('name', fn) // register a single hook
331
+ hooks.registerBatch({ name: fn }) // register multiple at once
332
+ hooks.has('name') // check if a hook exists → boolean
333
+ hooks.remove('name') // unregister a hook
334
+ ```
335
+
336
+ ---
337
+
338
+ ## Validation
339
+
340
+ Add a `validation` object to any API config to enforce rules on request fields.
341
+
342
+ ```js
343
+ {
344
+ type: 'CRUD',
345
+ operation: 'CREATE',
346
+ table: 'users',
347
+ columns: ['name', 'email'],
348
+ validation: {
349
+ name: { required: true, minLength: 2, maxLength: 100 },
350
+ email: { required: true, type: 'email' },
351
+ age: { type: 'number', min: 18 },
352
+ }
353
+ }
354
+ ```
355
+
356
+ Validation failures return HTTP `400` with a structured error:
357
+
358
+ ```json
359
+ {
360
+ "success": false,
361
+ "error": {
362
+ "message": "Validation failed",
363
+ "code": 400,
364
+ "details": [ ... ]
365
+ },
366
+ "timestamp": "2026-06-22T10:00:00.000Z"
367
+ }
368
+ ```
369
+
370
+ ---
371
+
372
+ ## Filters & Pagination
373
+
374
+ ### Filters
375
+
376
+ List field names in the `filters` array. DAB maps them from query parameters to SQL `WHERE` clauses automatically.
377
+
378
+ ```
379
+ GET /users?status=active&role=admin
380
+ ```
381
+
382
+ Use `filterConfig` to customize operators:
383
+
384
+ ```js
385
+ filterConfig: {
386
+ name: { operator: 'LIKE' }, // WHERE name LIKE '%value%'
387
+ age: { operator: '>=' },
388
+ orFields: ['name', 'email'] // WHERE (name = ? OR email = ?)
389
+ }
390
+ ```
391
+
392
+ Pass comma-separated values for an `IN` clause:
393
+
394
+ ```
395
+ GET /users?role=admin,manager
396
+ ```
397
+
398
+ ### Pagination
399
+
400
+ Enable with `pagination: true`. Control via query params:
401
+
402
+ ```
403
+ GET /users?page=2&limit=20
404
+ ```
405
+
406
+ ---
407
+
408
+ ## Joins
409
+
410
+ ```js
411
+ joins: [
412
+ {
413
+ type: 'LEFT', // 'INNER' | 'LEFT' | 'RIGHT'
414
+ table: 'roles',
415
+ condition: 'users.role_id = roles.id'
416
+ }
417
+ ]
418
+ ```
419
+
420
+ ---
421
+
422
+ ## Response Format
423
+
424
+ All responses follow a consistent structure.
425
+
426
+ **Success:**
427
+ ```json
428
+ {
429
+ "success": true,
430
+ "data": { ... },
431
+ "timestamp": "2026-06-22T10:00:00.000Z"
432
+ }
433
+ ```
434
+
435
+ **Error:**
436
+ ```json
437
+ {
438
+ "success": false,
439
+ "error": {
440
+ "message": "Duplicate entry",
441
+ "code": 409,
442
+ "details": null
443
+ },
444
+ "timestamp": "2026-06-22T10:00:00.000Z"
445
+ }
446
+ ```
447
+
448
+ DAB automatically maps common database error codes (duplicate entry, foreign key violation, null constraint, missing table) to appropriate HTTP status codes.
449
+
450
+ ---
451
+
452
+ ## Advanced Usage
453
+
454
+ ### Attaching middleware
455
+
456
+ Pass a `middleware` option to `dabApi()` to run middleware before every registered route:
457
+
458
+ ```js
459
+ const { router } = dabApi(config, {
460
+ middleware: [authMiddleware, rateLimitMiddleware]
461
+ });
462
+ ```
463
+
464
+ ### Accessing sub-modules
465
+
466
+ `dabApi()` returns an object with all internal modules exposed:
467
+
468
+ ```js
469
+ const { router, validator, executor, queryBuilder, hooks, response } = dabApi(config);
470
+ ```
471
+
472
+ ### Running raw queries
473
+
474
+ ```js
475
+ const { queryBuilder } = dabApi(config);
476
+
477
+ await queryBuilder.initPool();
478
+ const rows = await queryBuilder.execute('SELECT * FROM users WHERE id = ?', [1]);
479
+ ```
480
+
481
+ ### Transactions
482
+
483
+ ```js
484
+ await queryBuilder.beginTransaction();
485
+ try {
486
+ await queryBuilder.execute('UPDATE accounts SET balance = balance - ? WHERE id = ?', [100, 1]);
487
+ await queryBuilder.execute('UPDATE accounts SET balance = balance + ? WHERE id = ?', [100, 2]);
488
+ await queryBuilder.commitTransaction();
489
+ } catch (err) {
490
+ await queryBuilder.rollbackTransaction();
491
+ throw err;
492
+ }
493
+ ```
494
+
495
+ ---
496
+
497
+ ## API Reference
498
+
499
+ ### `dabApi(config, options?)`
500
+
501
+ Main entry point. Returns `{ router, validator, executor, queryBuilder, hooks, response }`.
502
+
503
+ | Param | Type | Description |
504
+ |--------------------|------------|------------------------------------------|
505
+ | `config.database` | `object` | DB connection config (optional if pool already configured) |
506
+ | `config.apis` | `array` | Array of API definitions (required) |
507
+ | `options.middleware` | `fn\|fn[]` | Middleware to run before every route |
508
+
509
+ ### `DabQueryBuilder`
510
+
511
+ | Method | Description |
512
+ |---------------------------------|------------------------------------------|
513
+ | `configure(config)` | Set DB config and initialize pool |
514
+ | `initPool()` | Open and verify the connection pool |
515
+ | `execute(sql, params)` | Run a raw parameterized query |
516
+ | `beginTransaction()` | Start a DB transaction |
517
+ | `commitTransaction()` | Commit the active transaction |
518
+ | `rollbackTransaction()` | Roll back the active transaction |
519
+ | `closePool()` | Drain and close the pool |
520
+
521
+ ### `DabHooks`
522
+
523
+ | Method | Description |
524
+ |-------------------------------|------------------------------------------|
525
+ | `register(name, fn)` | Register a hook function |
526
+ | `registerBatch(obj)` | Register multiple hooks |
527
+ | `execute(name, req, data?)` | Execute a registered hook |
528
+ | `has(name)` | Check if a hook is registered |
529
+ | `remove(name)` | Unregister a hook |
530
+
531
+ ---
532
+
533
+ ## Author
534
+
535
+ **Gulshan Marandi**
536
+
537
+ ---
538
+
539
+ ## License
540
+
541
+ ISC