lieko-express 0.0.2 β 0.0.4
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 +478 -78
- package/lieko-express.js +492 -127
- package/package.json +7 -2
package/README.md
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
#
|
|
1
|
+
# **Lieko-express β A Modern, Minimal, REST API Framework for Node.js**
|
|
2
2
|
|
|
3
3
|
A lightweight, fast, and modern Node.js REST API framework built on top of the native `http` module. Zero external dependencies for core functionality.
|
|
4
4
|
|
|
@@ -10,6 +10,10 @@ A lightweight, fast, and modern Node.js REST API framework built on top of the n
|
|
|
10
10
|
|
|
11
11
|
[](https://opensource.org/licenses/MIT)
|
|
12
12
|
[](https://nodejs.org)
|
|
13
|
+
[](https://www.npmjs.com/package/lieko-express)
|
|
14
|
+
|
|
15
|
+
[](https://github.com/eiwSrvt/lieko-express)
|
|
16
|
+
[](https://discord.gg/EpgPqjvd)
|
|
13
17
|
|
|
14
18
|
|
|
15
19
|
|
|
@@ -102,7 +106,7 @@ app.get('/', (req, res) => {
|
|
|
102
106
|
app.listen(3000, () => {
|
|
103
107
|
console.log('Server running on port 3000');
|
|
104
108
|
});
|
|
105
|
-
|
|
109
|
+
```
|
|
106
110
|
|
|
107
111
|
## π― Basic Usage
|
|
108
112
|
|
|
@@ -164,9 +168,13 @@ app.delete('/posts/:id', deletePost);
|
|
|
164
168
|
### Features
|
|
165
169
|
|
|
166
170
|
β Params automatically extracted
|
|
171
|
+
|
|
167
172
|
β Query auto-typed
|
|
173
|
+
|
|
168
174
|
β Body parsed and typed
|
|
175
|
+
|
|
169
176
|
β Wildcards available
|
|
177
|
+
|
|
170
178
|
β Trailing slashes handled intelligently
|
|
171
179
|
|
|
172
180
|
---
|
|
@@ -201,7 +209,7 @@ app.group('/api', auth, (api) => {
|
|
|
201
209
|
* You can nest indefinitely
|
|
202
210
|
* Works inside routers too
|
|
203
211
|
|
|
204
|
-
|
|
212
|
+
|
|
205
213
|
|
|
206
214
|
# π¦ Nested Routers
|
|
207
215
|
|
|
@@ -210,11 +218,11 @@ Routers are fully nestable:
|
|
|
210
218
|
```js
|
|
211
219
|
const { Router } = require('lieko-express');
|
|
212
220
|
|
|
213
|
-
const
|
|
221
|
+
const app = Router();
|
|
214
222
|
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
223
|
+
app.get('/', listUsers);
|
|
224
|
+
app.post('/', createUser);
|
|
225
|
+
app.get('/:id', getUser);
|
|
218
226
|
|
|
219
227
|
app.group('/api', auth, (api) => {
|
|
220
228
|
api.group('/admin', requireAdmin, (admin) => {
|
|
@@ -243,12 +251,13 @@ api.group(
|
|
|
243
251
|
}
|
|
244
252
|
);
|
|
245
253
|
```
|
|
246
|
-
|
|
254
|
+
β Router inherits middleware from its parent groups
|
|
255
|
+
|
|
256
|
+
β Paths automatically expanded
|
|
257
|
+
|
|
258
|
+
β Perfect for modular architecture
|
|
247
259
|
|
|
248
|
-
### β Paths automatically expanded
|
|
249
260
|
|
|
250
|
-
### β Perfect for modular architecture
|
|
251
|
-
---
|
|
252
261
|
# π§© API Versioning
|
|
253
262
|
|
|
254
263
|
With groups, versioning becomes trivial:
|
|
@@ -263,7 +272,6 @@ app.group('/api/v2', (v2) => {
|
|
|
263
272
|
});
|
|
264
273
|
```
|
|
265
274
|
|
|
266
|
-
---
|
|
267
275
|
|
|
268
276
|
### Query Parameters
|
|
269
277
|
|
|
@@ -291,7 +299,6 @@ app.get('/search', (req, res) => {
|
|
|
291
299
|
- `"true"` β `true` (boolean)
|
|
292
300
|
- `"false"` β `false` (boolean)
|
|
293
301
|
|
|
294
|
-
---
|
|
295
302
|
|
|
296
303
|
## π§ Middlewares
|
|
297
304
|
|
|
@@ -304,7 +311,7 @@ app.use((req, res, next) => {
|
|
|
304
311
|
next();
|
|
305
312
|
});
|
|
306
313
|
|
|
307
|
-
// CORS middleware
|
|
314
|
+
// CORS middleware (native, but you can use app.cors())
|
|
308
315
|
app.use((req, res, next) => {
|
|
309
316
|
res.set('Access-Control-Allow-Origin', '*');
|
|
310
317
|
res.set('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE');
|
|
@@ -375,8 +382,381 @@ app.use(async (req, res, next) => {
|
|
|
375
382
|
});
|
|
376
383
|
```
|
|
377
384
|
|
|
385
|
+
# **CORS**
|
|
386
|
+
|
|
387
|
+
|
|
388
|
+
Lieko-Express includes a **fully built-in, high-performance CORS engine**, with:
|
|
389
|
+
|
|
390
|
+
* Global CORS (`app.cors()`)
|
|
391
|
+
* Route-level CORS (`app.get("/test", { cors: {...} }, handler)`βcoming soon if you want it)
|
|
392
|
+
* Wildcard origins (`https://*.example.com`)
|
|
393
|
+
* Multiple allowed origins
|
|
394
|
+
* Strict mode (reject unknown origins)
|
|
395
|
+
* Credential support
|
|
396
|
+
* Private Network Access (Chrome PNA)
|
|
397
|
+
* Debug logging
|
|
398
|
+
* Full OPTIONS preflight support
|
|
399
|
+
|
|
400
|
+
---
|
|
401
|
+
|
|
402
|
+
# **Enable CORS Globally**
|
|
403
|
+
|
|
404
|
+
```js
|
|
405
|
+
app.cors();
|
|
406
|
+
```
|
|
407
|
+
|
|
408
|
+
This enables default permissive CORS:
|
|
409
|
+
|
|
410
|
+
| Option | Default |
|
|
411
|
+
| --------------------- | ----------------------------- |
|
|
412
|
+
| `origin` | `"*"` |
|
|
413
|
+
| `methods` | all standard methods |
|
|
414
|
+
| `headers` | `Content-Type, Authorization` |
|
|
415
|
+
| `credentials` | false |
|
|
416
|
+
| `maxAge` | 86400 (24h) |
|
|
417
|
+
| `exposedHeaders` | none |
|
|
418
|
+
| `strictOrigin` | false |
|
|
419
|
+
| `allowPrivateNetwork` | false |
|
|
420
|
+
|
|
421
|
+
---
|
|
422
|
+
|
|
423
|
+
# **Custom Global CORS Options**
|
|
424
|
+
|
|
425
|
+
```js
|
|
426
|
+
app.cors({
|
|
427
|
+
origin: ["https://example.com", "https://api.example.com"],
|
|
428
|
+
methods: ["GET", "POST"],
|
|
429
|
+
headers: ["Content-Type", "Authorization", "X-Custom"],
|
|
430
|
+
credentials: true,
|
|
431
|
+
maxAge: 3600,
|
|
432
|
+
exposedHeaders: ["X-RateLimit-Remaining"],
|
|
433
|
+
});
|
|
434
|
+
```
|
|
435
|
+
|
|
436
|
+
---
|
|
437
|
+
|
|
438
|
+
# **Allow All Origins (Standard Mode)**
|
|
439
|
+
|
|
440
|
+
```js
|
|
441
|
+
app.cors({
|
|
442
|
+
origin: "*"
|
|
443
|
+
});
|
|
444
|
+
```
|
|
445
|
+
|
|
446
|
+
β οΈ If you also set `credentials: true`, browsers will **reject** `*`.
|
|
447
|
+
Lieko will still output `*` because that's the correct spec behavior.
|
|
448
|
+
|
|
449
|
+
---
|
|
450
|
+
|
|
451
|
+
# **Strict Origin Mode**
|
|
452
|
+
|
|
453
|
+
Strict mode ensures the incoming `Origin` header **must match exactly** one of your allowed origins.
|
|
454
|
+
|
|
455
|
+
```js
|
|
456
|
+
app.cors({
|
|
457
|
+
origin: ["https://myapp.com"],
|
|
458
|
+
strictOrigin: true
|
|
459
|
+
});
|
|
460
|
+
```
|
|
461
|
+
|
|
462
|
+
If the request comes from an unauthorized origin:
|
|
463
|
+
|
|
464
|
+
```json
|
|
465
|
+
HTTP 403
|
|
466
|
+
{
|
|
467
|
+
"success": false,
|
|
468
|
+
"error": "Origin Forbidden",
|
|
469
|
+
"message": "Origin \"https://evil.com\" is not allowed"
|
|
470
|
+
}
|
|
471
|
+
```
|
|
472
|
+
|
|
473
|
+
---
|
|
474
|
+
|
|
475
|
+
# **Wildcard Origins**
|
|
476
|
+
|
|
477
|
+
Lieko-Express supports Express-style wildcard patterns:
|
|
478
|
+
|
|
479
|
+
### Allow any subdomain
|
|
480
|
+
|
|
481
|
+
```js
|
|
482
|
+
app.cors({
|
|
483
|
+
origin: "https://*.example.com"
|
|
484
|
+
});
|
|
485
|
+
```
|
|
486
|
+
|
|
487
|
+
Matches:
|
|
488
|
+
|
|
489
|
+
* `https://api.example.com`
|
|
490
|
+
* `https://dashboard.example.com`
|
|
491
|
+
|
|
492
|
+
Does not match:
|
|
493
|
+
|
|
494
|
+
* `http://example.com`
|
|
495
|
+
* `https://example.net`
|
|
496
|
+
|
|
497
|
+
---
|
|
498
|
+
|
|
499
|
+
# **Allow Private Network Access (Chrome PNA)**
|
|
500
|
+
|
|
501
|
+
```js
|
|
502
|
+
app.cors({
|
|
503
|
+
allowPrivateNetwork: true
|
|
504
|
+
});
|
|
505
|
+
```
|
|
506
|
+
|
|
507
|
+
When Chrome sends:
|
|
508
|
+
|
|
509
|
+
```
|
|
510
|
+
Access-Control-Request-Private-Network: true
|
|
511
|
+
```
|
|
512
|
+
|
|
513
|
+
Lieko automatically responds:
|
|
514
|
+
|
|
515
|
+
```
|
|
516
|
+
Access-Control-Allow-Private-Network: true
|
|
517
|
+
```
|
|
518
|
+
|
|
519
|
+
# Route-Level CORS
|
|
520
|
+
|
|
521
|
+
Lieko-Express allows each route to override or extend the global CORS settings using a `cors` property in the route options.
|
|
522
|
+
This gives you fine-grained control over cross-origin behavior on a per-endpoint basis.
|
|
523
|
+
|
|
524
|
+
Route-level CORS:
|
|
525
|
+
|
|
526
|
+
* Overrides global CORS
|
|
527
|
+
* Supports wildcards (`https://*.example.com`)
|
|
528
|
+
* Supports strict mode
|
|
529
|
+
* Sends its own preflight response
|
|
530
|
+
* Automatically merges with the global configuration
|
|
531
|
+
* Does **not** affect other routes
|
|
532
|
+
|
|
533
|
+
---
|
|
534
|
+
|
|
535
|
+
## Basic Example
|
|
536
|
+
|
|
537
|
+
```js
|
|
538
|
+
app.get("/public", {
|
|
539
|
+
cors: { origin: "*" }
|
|
540
|
+
}, (req, res) => {
|
|
541
|
+
res.ok("Public endpoint with open CORS");
|
|
542
|
+
});
|
|
543
|
+
```
|
|
544
|
+
|
|
545
|
+
This route allows requests from **any origin**, even if global CORS is configured differently.
|
|
546
|
+
|
|
547
|
+
---
|
|
548
|
+
|
|
549
|
+
## π Restrict a Sensitive Route
|
|
550
|
+
|
|
551
|
+
```js
|
|
552
|
+
app.post("/admin/login", {
|
|
553
|
+
cors: {
|
|
554
|
+
origin: "https://dashboard.myapp.com",
|
|
555
|
+
credentials: true,
|
|
556
|
+
strictOrigin: true
|
|
557
|
+
}
|
|
558
|
+
}, (req, res) => {
|
|
559
|
+
res.ok("Login OK");
|
|
560
|
+
});
|
|
561
|
+
```
|
|
562
|
+
|
|
563
|
+
### Result:
|
|
564
|
+
|
|
565
|
+
* Only `https://dashboard.myapp.com` is allowed
|
|
566
|
+
* Cookies / sessions allowed
|
|
567
|
+
* Any other origin receives:
|
|
568
|
+
|
|
569
|
+
```json
|
|
570
|
+
{
|
|
571
|
+
"success": false,
|
|
572
|
+
"error": "Origin Forbidden",
|
|
573
|
+
"message": "Origin \"https://evil.com\" is not allowed"
|
|
574
|
+
}
|
|
575
|
+
```
|
|
576
|
+
|
|
577
|
+
Status: **403 Forbidden**
|
|
578
|
+
|
|
579
|
+
---
|
|
580
|
+
|
|
581
|
+
## β¨ Wildcard Origins on a Route
|
|
582
|
+
|
|
583
|
+
```js
|
|
584
|
+
app.get("/api/data", {
|
|
585
|
+
cors: {
|
|
586
|
+
origin: "https://*.example.com"
|
|
587
|
+
}
|
|
588
|
+
}, (req, res) => {
|
|
589
|
+
res.ok({ data: 123 });
|
|
590
|
+
});
|
|
591
|
+
```
|
|
592
|
+
|
|
593
|
+
Matches:
|
|
594
|
+
|
|
595
|
+
* `https://api.example.com`
|
|
596
|
+
* `https://dashboard.example.com`
|
|
597
|
+
|
|
598
|
+
---
|
|
599
|
+
|
|
600
|
+
## βοΈ Full Route-Level CORS Example
|
|
601
|
+
|
|
602
|
+
```js
|
|
603
|
+
app.get("/user/profile", {
|
|
604
|
+
cors: {
|
|
605
|
+
origin: [
|
|
606
|
+
"https://app.example.com",
|
|
607
|
+
"https://*.trusted.dev"
|
|
608
|
+
],
|
|
609
|
+
methods: ["GET", "PATCH"],
|
|
610
|
+
headers: ["Content-Type", "Authorization"],
|
|
611
|
+
exposedHeaders: ["X-User-Id"],
|
|
612
|
+
credentials: true,
|
|
613
|
+
maxAge: 600,
|
|
614
|
+
strictOrigin: true,
|
|
615
|
+
allowPrivateNetwork: true,
|
|
616
|
+
debug: true
|
|
617
|
+
}
|
|
618
|
+
}, (req, res) => {
|
|
619
|
+
res.ok({ profile: "OK" });
|
|
620
|
+
});
|
|
621
|
+
```
|
|
622
|
+
|
|
623
|
+
---
|
|
624
|
+
|
|
625
|
+
## π How Route-Level CORS Works Internally
|
|
626
|
+
|
|
627
|
+
When a request hits a route:
|
|
628
|
+
|
|
629
|
+
1. If global CORS is enabled β apply it.
|
|
630
|
+
2. If the route defines `cors` β merge with global config.
|
|
631
|
+
3. Route CORS **overrides** global CORS.
|
|
632
|
+
4. If request is `OPTIONS` (preflight) β return automatic CORS response.
|
|
633
|
+
5. Otherwise β run route handler.
|
|
634
|
+
|
|
635
|
+
This ensures predictable behavior.
|
|
636
|
+
|
|
378
637
|
---
|
|
379
638
|
|
|
639
|
+
## π Route-Level CORS Options
|
|
640
|
+
|
|
641
|
+
| Option | Type | Description | |
|
|
642
|
+
| --------------------- | ---------- | ---------------------------------------- | ---------------------------------------- |
|
|
643
|
+
| `origin` | `string | string[]` | Allowed origins (`*`, domain, wildcard). |
|
|
644
|
+
| `methods` | `string[]` | Allowed HTTP methods. | |
|
|
645
|
+
| `headers` | `string[]` | Allowed request headers. | |
|
|
646
|
+
| `exposedHeaders` | `string[]` | Response headers exposed to the browser. | |
|
|
647
|
+
| `credentials` | `boolean` | Allow cookies/sessions. | |
|
|
648
|
+
| `maxAge` | `number` | Preflight cache lifetime (seconds). | |
|
|
649
|
+
| `strictOrigin` | `boolean` | Reject non-matching origins with 403. | |
|
|
650
|
+
| `allowPrivateNetwork` | `boolean` | Enables Chrome Private Network Access. | |
|
|
651
|
+
| `debug` | `boolean` | Logs detailed CORS decisions. | |
|
|
652
|
+
|
|
653
|
+
---
|
|
654
|
+
|
|
655
|
+
## π§© Interaction with Global CORS
|
|
656
|
+
|
|
657
|
+
| Feature | Global | Route |
|
|
658
|
+
| ------------------ | ------ | ------------- |
|
|
659
|
+
| Origin | β | β (overrides) |
|
|
660
|
+
| Wildcards | β | β |
|
|
661
|
+
| Credentials | β | β |
|
|
662
|
+
| Strict Origin | β | β |
|
|
663
|
+
| Private Network | β | β |
|
|
664
|
+
| Debug Logging | β | β |
|
|
665
|
+
| Preflight Handling | β | β |
|
|
666
|
+
| Overrides Global | β | β |
|
|
667
|
+
|
|
668
|
+
|
|
669
|
+
|
|
670
|
+
|
|
671
|
+
# **Enable CORS Debug Logging**
|
|
672
|
+
|
|
673
|
+
```js
|
|
674
|
+
app.cors({
|
|
675
|
+
debug: true
|
|
676
|
+
});
|
|
677
|
+
```
|
|
678
|
+
|
|
679
|
+
Console output example:
|
|
680
|
+
|
|
681
|
+
```
|
|
682
|
+
[CORS DEBUG]
|
|
683
|
+
Request: GET /users
|
|
684
|
+
Origin: https://app.example.com
|
|
685
|
+
Applied CORS Policy:
|
|
686
|
+
- Access-Control-Allow-Origin: https://app.example.com
|
|
687
|
+
- Access-Control-Allow-Methods: GET, POST, PUT, PATCH, DELETE, OPTIONS
|
|
688
|
+
- Access-Control-Allow-Headers: Content-Type, Authorization
|
|
689
|
+
- Max-Age: 86400
|
|
690
|
+
Simple request handled normally
|
|
691
|
+
```
|
|
692
|
+
|
|
693
|
+
---
|
|
694
|
+
|
|
695
|
+
# **Preflight Handling (OPTIONS)**
|
|
696
|
+
|
|
697
|
+
Lieko-Express automatically handles it:
|
|
698
|
+
|
|
699
|
+
### Request:
|
|
700
|
+
|
|
701
|
+
```
|
|
702
|
+
OPTIONS /login
|
|
703
|
+
Access-Control-Request-Method: POST
|
|
704
|
+
Access-Control-Request-Headers: Content-Type
|
|
705
|
+
```
|
|
706
|
+
|
|
707
|
+
### Lieko Response:
|
|
708
|
+
|
|
709
|
+
```
|
|
710
|
+
204 No Content
|
|
711
|
+
Access-Control-Allow-Methods: GET, POST, PUT, PATCH, DELETE, OPTIONS
|
|
712
|
+
Access-Control-Allow-Headers: Content-Type, Authorization
|
|
713
|
+
Access-Control-Max-Age: 86400
|
|
714
|
+
```
|
|
715
|
+
|
|
716
|
+
---
|
|
717
|
+
|
|
718
|
+
# **Credentials Support**
|
|
719
|
+
|
|
720
|
+
```js
|
|
721
|
+
app.cors({
|
|
722
|
+
credentials: true,
|
|
723
|
+
origin: "https://myapp.com"
|
|
724
|
+
});
|
|
725
|
+
```
|
|
726
|
+
|
|
727
|
+
Response contains:
|
|
728
|
+
|
|
729
|
+
```
|
|
730
|
+
Access-Control-Allow-Credentials: true
|
|
731
|
+
```
|
|
732
|
+
|
|
733
|
+
---
|
|
734
|
+
|
|
735
|
+
|
|
736
|
+
# **Disable CORS**
|
|
737
|
+
|
|
738
|
+
Just donβt call `app.cors()`.
|
|
739
|
+
CORS stays fully disabled.
|
|
740
|
+
|
|
741
|
+
---
|
|
742
|
+
|
|
743
|
+
# **Default CORS Configuration**
|
|
744
|
+
|
|
745
|
+
```js
|
|
746
|
+
this.corsOptions = {
|
|
747
|
+
enabled: false,
|
|
748
|
+
origin: "*",
|
|
749
|
+
strictOrigin: false,
|
|
750
|
+
allowPrivateNetwork: false,
|
|
751
|
+
methods: ["GET", "POST", "PUT", "PATCH", "DELETE", "OPTIONS"],
|
|
752
|
+
headers: ["Content-Type", "Authorization"],
|
|
753
|
+
credentials: false,
|
|
754
|
+
maxAge: 86400,
|
|
755
|
+
exposedHeaders: [],
|
|
756
|
+
debug: false
|
|
757
|
+
};
|
|
758
|
+
```
|
|
759
|
+
|
|
380
760
|
# π Request Object
|
|
381
761
|
|
|
382
762
|
Liekoβs `req` object provides:
|
|
@@ -414,8 +794,6 @@ Lieko safely handles:
|
|
|
414
794
|
* IPv4-mapped IPv6
|
|
415
795
|
* Multiple proxies
|
|
416
796
|
|
|
417
|
-
---
|
|
418
|
-
|
|
419
797
|
|
|
420
798
|
# π― Response Object (`res`)
|
|
421
799
|
|
|
@@ -434,7 +812,6 @@ Lieko enhances Node's native response object with convenient helper methods.
|
|
|
434
812
|
| `res.json(obj)` | Sends JSON with correct headers. |
|
|
435
813
|
| `res.end(body)` | Ends the response manually. |
|
|
436
814
|
|
|
437
|
-
---
|
|
438
815
|
|
|
439
816
|
# β
**High-Level Helpers**
|
|
440
817
|
|
|
@@ -447,7 +824,6 @@ Lieko enhances Node's native response object with convenient helper methods.
|
|
|
447
824
|
| `res.noContent()` | Sends status `204` with no body. |
|
|
448
825
|
| `res.paginated(payload)` | Standard API pagination output. |
|
|
449
826
|
|
|
450
|
-
---
|
|
451
827
|
|
|
452
828
|
# β **Error Helpers**
|
|
453
829
|
|
|
@@ -466,8 +842,6 @@ Lieko enhances Node's native response object with convenient helper methods.
|
|
|
466
842
|
> { "success": false, "error": { "code": "...", "message": "..." } }
|
|
467
843
|
> ```
|
|
468
844
|
|
|
469
|
-
---
|
|
470
|
-
|
|
471
845
|
# π§ **Content-Type Helpers**
|
|
472
846
|
|
|
473
847
|
### **HTML**
|
|
@@ -482,7 +856,6 @@ Lieko enhances Node's native response object with convenient helper methods.
|
|
|
482
856
|
| -------------------------- | ------------------------------------- |
|
|
483
857
|
| `res.redirect(url, code?)` | Redirects the client (default `302`). |
|
|
484
858
|
|
|
485
|
-
---
|
|
486
859
|
|
|
487
860
|
# π¦ **Low-Level Output Controls**
|
|
488
861
|
|
|
@@ -516,16 +889,82 @@ res.paginated(items, page, limit, total);
|
|
|
516
889
|
* String errors also supported (`res.error("Invalid user")`)
|
|
517
890
|
|
|
518
891
|
---
|
|
892
|
+
# Body Parsing (JSON, URL-encoded, Multipart) β 100% Native, Zero Dependencies
|
|
893
|
+
|
|
894
|
+
Lieko Express ships with a **fast, secure, and fully native body parser** β no external packages, not even `body-parser`.
|
|
519
895
|
|
|
520
|
-
|
|
896
|
+
As soon as you create your app, body parsing is **automatically enabled**:
|
|
521
897
|
|
|
522
|
-
|
|
898
|
+
```js
|
|
899
|
+
const app = Lieko(); // Ready to handle JSON, form-data, files, etc.
|
|
900
|
+
```
|
|
901
|
+
|
|
902
|
+
### Default Limits
|
|
903
|
+
|
|
904
|
+
| Content-Type | Default Limit | Bytes |
|
|
905
|
+
|---------------------------------------|---------------|-------------------|
|
|
906
|
+
| `application/json` | **1mb** | ~1,048,576 bytes |
|
|
907
|
+
| `application/x-www-form-urlencoded` | **1mb** | ~1,048,576 bytes |
|
|
908
|
+
| `multipart/form-data` (file uploads) | **10mb** | ~10,485,760 bytes |
|
|
909
|
+
|
|
910
|
+
Thatβs already **10Γ more generous** than Expressβs default 100kb!
|
|
911
|
+
|
|
912
|
+
### Change Limits β Three Super-Simple Ways
|
|
913
|
+
|
|
914
|
+
#### 1. Per content-type (most common)
|
|
915
|
+
|
|
916
|
+
```js
|
|
917
|
+
app.json({ limit: '100mb' }); // JSON payloads only
|
|
918
|
+
app.urlencoded({ limit: '50mb' }); // Classic HTML forms
|
|
919
|
+
```
|
|
523
920
|
|
|
524
|
-
|
|
921
|
+
#### 2. Global limit (JSON + urlencoded at once)
|
|
525
922
|
|
|
526
|
-
|
|
923
|
+
```js
|
|
924
|
+
app.bodyParser({ limit: '50mb' });
|
|
925
|
+
// Applies 50mb to both JSON and urlencoded bodies
|
|
926
|
+
```
|
|
527
927
|
|
|
528
|
-
|
|
928
|
+
#### 3. File upload limit (multipart/form-data)
|
|
929
|
+
|
|
930
|
+
```js
|
|
931
|
+
app.multipart({ limit: '500mb' }); // For very large file uploads
|
|
932
|
+
```
|
|
933
|
+
|
|
934
|
+
You can freely combine them:
|
|
935
|
+
|
|
936
|
+
```js
|
|
937
|
+
const app = Lieko();
|
|
938
|
+
|
|
939
|
+
app.json({ limit: '10mb' }); // Small, fast JSON APIs
|
|
940
|
+
app.urlencoded({ limit: '5mb' });
|
|
941
|
+
app.multipart({ limit: '1gb' }); // Allow huge file uploads
|
|
942
|
+
```
|
|
943
|
+
|
|
944
|
+
### Real-world Example
|
|
945
|
+
|
|
946
|
+
```js
|
|
947
|
+
const Lieko = require('lieko-express');
|
|
948
|
+
const app = Lieko();
|
|
949
|
+
|
|
950
|
+
// Accept reasonably large JSON payloads
|
|
951
|
+
app.json({ limit: '25mb' });
|
|
952
|
+
|
|
953
|
+
// Accept classic forms
|
|
954
|
+
app.urlencoded({ limit: '10mb' });
|
|
955
|
+
|
|
956
|
+
// Allow big file uploads (photos, videos, etc.)
|
|
957
|
+
app.multipart({ limit: '500mb' });
|
|
958
|
+
|
|
959
|
+
app.post('/upload', (req, res) => {
|
|
960
|
+
console.log('JSON body size :', Buffer.byteLength(JSON.stringify(req.body)), 'bytes');
|
|
961
|
+
console.log('Uploaded files :', Object.keys(req.files || {}));
|
|
962
|
+
|
|
963
|
+
res.ok({ received: true, files: req.files });
|
|
964
|
+
});
|
|
965
|
+
|
|
966
|
+
app.listen(3000);
|
|
967
|
+
```
|
|
529
968
|
|
|
530
969
|
Uploads end up in:
|
|
531
970
|
|
|
@@ -549,6 +988,12 @@ Query & body fields are **auto converted**:
|
|
|
549
988
|
"null" β null
|
|
550
989
|
```
|
|
551
990
|
|
|
991
|
+
|
|
992
|
+
**No `app.use(express.json())`, no `app.use(express.urlencoded())`, no extra dependencies** β everything works out of the box, blazing fast, and fully configurable in one line.
|
|
993
|
+
|
|
994
|
+
Thatβs the Lieko philosophy: **less boilerplate, more power**.
|
|
995
|
+
|
|
996
|
+
|
|
552
997
|
### Response Methods
|
|
553
998
|
|
|
554
999
|
```javascript
|
|
@@ -621,8 +1066,6 @@ app.post('/upload', (req, res) => {
|
|
|
621
1066
|
});
|
|
622
1067
|
```
|
|
623
1068
|
|
|
624
|
-
---
|
|
625
|
-
|
|
626
1069
|
## β
Validation
|
|
627
1070
|
|
|
628
1071
|
### Built-in Validators
|
|
@@ -740,8 +1183,6 @@ const userSchema = schema({
|
|
|
740
1183
|
});
|
|
741
1184
|
```
|
|
742
1185
|
|
|
743
|
-
---
|
|
744
|
-
|
|
745
1186
|
## **Boolean Example**
|
|
746
1187
|
|
|
747
1188
|
```js
|
|
@@ -758,8 +1199,6 @@ Accepted:
|
|
|
758
1199
|
true, false, "true", "false", 1, 0, "1", "0"
|
|
759
1200
|
```
|
|
760
1201
|
|
|
761
|
-
---
|
|
762
|
-
|
|
763
1202
|
## **Email Example**
|
|
764
1203
|
|
|
765
1204
|
```js
|
|
@@ -771,8 +1210,6 @@ const schema = schema({
|
|
|
771
1210
|
});
|
|
772
1211
|
```
|
|
773
1212
|
|
|
774
|
-
---
|
|
775
|
-
|
|
776
1213
|
## **Username with rules**
|
|
777
1214
|
|
|
778
1215
|
```js
|
|
@@ -787,8 +1224,6 @@ const usernameSchema = schema({
|
|
|
787
1224
|
});
|
|
788
1225
|
```
|
|
789
1226
|
|
|
790
|
-
---
|
|
791
|
-
|
|
792
1227
|
## **Password strength**
|
|
793
1228
|
|
|
794
1229
|
```js
|
|
@@ -806,8 +1241,6 @@ const passwordSchema = schema({
|
|
|
806
1241
|
});
|
|
807
1242
|
```
|
|
808
1243
|
|
|
809
|
-
---
|
|
810
|
-
|
|
811
1244
|
## **Multiple-choice fields**
|
|
812
1245
|
|
|
813
1246
|
```js
|
|
@@ -818,7 +1251,6 @@ const roleSchema = schema({
|
|
|
818
1251
|
});
|
|
819
1252
|
```
|
|
820
1253
|
|
|
821
|
-
---
|
|
822
1254
|
|
|
823
1255
|
## **Blacklist Example**
|
|
824
1256
|
|
|
@@ -830,8 +1262,6 @@ const schema = schema({
|
|
|
830
1262
|
});
|
|
831
1263
|
```
|
|
832
1264
|
|
|
833
|
-
---
|
|
834
|
-
|
|
835
1265
|
## **Starts / Ends With**
|
|
836
1266
|
|
|
837
1267
|
```js
|
|
@@ -842,11 +1272,9 @@ const schema = schema({
|
|
|
842
1272
|
});
|
|
843
1273
|
```
|
|
844
1274
|
|
|
845
|
-
---
|
|
846
|
-
|
|
847
1275
|
# **Advanced Validation Examples**
|
|
848
1276
|
|
|
849
|
-
|
|
1277
|
+
|
|
850
1278
|
|
|
851
1279
|
## **Cross-field validation (matching passwords)**
|
|
852
1280
|
|
|
@@ -863,7 +1291,6 @@ const registerSchema = schema({
|
|
|
863
1291
|
});
|
|
864
1292
|
```
|
|
865
1293
|
|
|
866
|
-
---
|
|
867
1294
|
|
|
868
1295
|
## Conditional Validation (depends on another field)
|
|
869
1296
|
|
|
@@ -880,7 +1307,6 @@ const orderSchema = schema({
|
|
|
880
1307
|
});
|
|
881
1308
|
```
|
|
882
1309
|
|
|
883
|
-
---
|
|
884
1310
|
|
|
885
1311
|
## Dynamic rules EX: `age` required only if user is not admin
|
|
886
1312
|
|
|
@@ -896,7 +1322,6 @@ const schema = schema({
|
|
|
896
1322
|
});
|
|
897
1323
|
```
|
|
898
1324
|
|
|
899
|
-
---
|
|
900
1325
|
|
|
901
1326
|
## **Date validation**
|
|
902
1327
|
|
|
@@ -912,7 +1337,6 @@ const eventSchema = schema({
|
|
|
912
1337
|
});
|
|
913
1338
|
```
|
|
914
1339
|
|
|
915
|
-
---
|
|
916
1340
|
|
|
917
1341
|
# **Combining many validators**
|
|
918
1342
|
|
|
@@ -928,7 +1352,6 @@ const schema = schema({
|
|
|
928
1352
|
});
|
|
929
1353
|
```
|
|
930
1354
|
|
|
931
|
-
---
|
|
932
1355
|
|
|
933
1356
|
# **Optional field + rules if provided**
|
|
934
1357
|
|
|
@@ -945,7 +1368,6 @@ const schema = schema({
|
|
|
945
1368
|
If nickname is empty β no validation.
|
|
946
1369
|
If present β must follow rules.
|
|
947
1370
|
|
|
948
|
-
---
|
|
949
1371
|
|
|
950
1372
|
# **Example of validation error response**
|
|
951
1373
|
|
|
@@ -1014,7 +1436,6 @@ const orderSchema = schema({
|
|
|
1014
1436
|
});
|
|
1015
1437
|
```
|
|
1016
1438
|
|
|
1017
|
-
---
|
|
1018
1439
|
|
|
1019
1440
|
## ποΈ Routers
|
|
1020
1441
|
|
|
@@ -1138,8 +1559,6 @@ app.use('/api/posts', postsRouter);
|
|
|
1138
1559
|
app.listen(3000);
|
|
1139
1560
|
```
|
|
1140
1561
|
|
|
1141
|
-
---
|
|
1142
|
-
|
|
1143
1562
|
## β οΈ Error Handling
|
|
1144
1563
|
|
|
1145
1564
|
### Custom 404 Handler
|
|
@@ -1208,7 +1627,6 @@ res.error({ code: 'CUSTOM_ERROR', status: 418 });
|
|
|
1208
1627
|
}
|
|
1209
1628
|
```
|
|
1210
1629
|
|
|
1211
|
-
---
|
|
1212
1630
|
|
|
1213
1631
|
## π₯ Advanced Examples
|
|
1214
1632
|
|
|
@@ -1551,7 +1969,6 @@ const requestLogger = (req, res, next) => {
|
|
|
1551
1969
|
app.use(requestLogger);
|
|
1552
1970
|
```
|
|
1553
1971
|
|
|
1554
|
-
---
|
|
1555
1972
|
|
|
1556
1973
|
## π― Complete Application Example
|
|
1557
1974
|
|
|
@@ -1564,7 +1981,6 @@ See the [examples](./examples) directory for a full-featured application with:
|
|
|
1564
1981
|
- Middleware examples
|
|
1565
1982
|
- Comprehensive test suite
|
|
1566
1983
|
|
|
1567
|
-
---
|
|
1568
1984
|
|
|
1569
1985
|
# π Performance Tips (Suite)
|
|
1570
1986
|
|
|
@@ -1575,7 +1991,6 @@ See the [examples](./examples) directory for a full-featured application with:
|
|
|
1575
1991
|
5. **Use reverse proxy headers correctly** (`trust proxy`) when hosting behind Nginx
|
|
1576
1992
|
6. **Disable console logs in production** or use a real logger with adjustable log levels
|
|
1577
1993
|
|
|
1578
|
-
---
|
|
1579
1994
|
|
|
1580
1995
|
## Debug & Introspection Tools
|
|
1581
1996
|
|
|
@@ -1610,6 +2025,7 @@ DEBUG REQUEST
|
|
|
1610
2025
|
β Params: {"id":"42"}
|
|
1611
2026
|
β Query: {"page":2,"active":true}
|
|
1612
2027
|
β Body: {}
|
|
2028
|
+
β Body Size: 0 bytes
|
|
1613
2029
|
β Files:
|
|
1614
2030
|
---------------------------------------------
|
|
1615
2031
|
```
|
|
@@ -1682,9 +2098,9 @@ You can configure:
|
|
|
1682
2098
|
```js
|
|
1683
2099
|
app.set('trust proxy', value);
|
|
1684
2100
|
app.set('debug', boolean);
|
|
1685
|
-
app.set('x-powered-by',
|
|
1686
|
-
app.set('strictTrailingSlash',
|
|
1687
|
-
app.set('allowTrailingSlash',
|
|
2101
|
+
app.set('x-powered-by', boolean);
|
|
2102
|
+
app.set('strictTrailingSlash', boolean);
|
|
2103
|
+
app.set('allowTrailingSlash', boolean);
|
|
1688
2104
|
```
|
|
1689
2105
|
|
|
1690
2106
|
# π Trust Proxy & IP Parsing
|
|
@@ -1720,7 +2136,6 @@ Lieko correctly handles:
|
|
|
1720
2136
|
* IPv4-mapped IPv6 (`::ffff:127.0.0.1`)
|
|
1721
2137
|
* Multi-proxy headers
|
|
1722
2138
|
|
|
1723
|
-
---
|
|
1724
2139
|
|
|
1725
2140
|
## π§© Internals & Architecture
|
|
1726
2141
|
|
|
@@ -1754,8 +2169,6 @@ This allows:
|
|
|
1754
2169
|
* Fast matching
|
|
1755
2170
|
|
|
1756
2171
|
|
|
1757
|
-
---
|
|
1758
|
-
|
|
1759
2172
|
## π§± Extending Lieko Express
|
|
1760
2173
|
|
|
1761
2174
|
Because the framework is intentionally small, you can easily extend it.
|
|
@@ -1786,8 +2199,6 @@ const timing = (req, res, next) => {
|
|
|
1786
2199
|
app.use(timing);
|
|
1787
2200
|
```
|
|
1788
2201
|
|
|
1789
|
-
---
|
|
1790
|
-
|
|
1791
2202
|
# π Plugins
|
|
1792
2203
|
|
|
1793
2204
|
A plugin is simply a function receiving `app`:
|
|
@@ -1799,16 +2210,6 @@ function myPlugin(app) {
|
|
|
1799
2210
|
|
|
1800
2211
|
myPlugin(app);
|
|
1801
2212
|
```
|
|
1802
|
-
---
|
|
1803
|
-
|
|
1804
|
-
## π Deploying Lieko Express
|
|
1805
|
-
|
|
1806
|
-
### Node.js (PM2)
|
|
1807
|
-
|
|
1808
|
-
```bash
|
|
1809
|
-
pm2 start app.js
|
|
1810
|
-
```
|
|
1811
|
-
|
|
1812
2213
|
## π¦ API Reference
|
|
1813
2214
|
|
|
1814
2215
|
### `Lieko()`
|
|
@@ -1862,7 +2263,7 @@ app.notFound((req, res) => {
|
|
|
1862
2263
|
|
|
1863
2264
|
Register a custom 500 handler.
|
|
1864
2265
|
|
|
1865
|
-
|
|
2266
|
+
|
|
1866
2267
|
|
|
1867
2268
|
## π Known Limitations
|
|
1868
2269
|
|
|
@@ -1876,7 +2277,6 @@ Because Lieko Express is minimalistic:
|
|
|
1876
2277
|
|
|
1877
2278
|
Future versions may address some of these.
|
|
1878
2279
|
|
|
1879
|
-
---
|
|
1880
2280
|
|
|
1881
2281
|
## π€ Contributing
|
|
1882
2282
|
|
|
@@ -1887,7 +2287,7 @@ Contributions are welcome!
|
|
|
1887
2287
|
3. Commit your changes
|
|
1888
2288
|
4. Open a pull request
|
|
1889
2289
|
|
|
1890
|
-
|
|
2290
|
+
|
|
1891
2291
|
|
|
1892
2292
|
## π License
|
|
1893
2293
|
|