@syntay/fastay 0.2.9 → 1.0.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.
- package/README.md +13 -1434
- package/dist/app.d.ts +24 -41
- package/dist/app.d.ts.map +1 -1
- package/dist/app.js +141 -53
- package/dist/error-handler.d.ts +13 -2
- package/dist/error-handler.d.ts.map +1 -1
- package/dist/error-handler.js +164 -30
- package/dist/error-hanler2.d.ts +14 -0
- package/dist/error-hanler2.d.ts.map +1 -0
- package/dist/error-hanler2.js +180 -0
- package/dist/logger.d.ts.map +1 -1
- package/dist/logger.js +14 -18
- package/dist/middleware.d.ts +2 -1
- package/dist/middleware.d.ts.map +1 -1
- package/dist/middleware.js +12 -12
- package/dist/router.d.ts +3 -9
- package/dist/router.d.ts.map +1 -1
- package/dist/router.js +169 -155
- package/dist/utils/wrapMiddleware.d.ts +2 -1
- package/dist/utils/wrapMiddleware.d.ts.map +1 -1
- package/dist/utils/wrapMiddleware.js +10 -0
- package/package.json +11 -3
package/README.md
CHANGED
|
@@ -1,8 +1,6 @@
|
|
|
1
|
-
# Fastay
|
|
1
|
+
# Fastay
|
|
2
2
|
|
|
3
3
|
<p align="center">
|
|
4
|
-
<img src="./fastay.png" width="200" />
|
|
5
|
-
<br>
|
|
6
4
|
<a href="https://www.npmjs.com/package/@syntay/fastay">
|
|
7
5
|
<img src="https://img.shields.io/npm/v/@syntay/fastay.svg?style=flat-square" alt="npm version">
|
|
8
6
|
</a>
|
|
@@ -17,1454 +15,35 @@
|
|
|
17
15
|
</a>
|
|
18
16
|
</p>
|
|
19
17
|
|
|
20
|
-
Fastay is a modern backend framework built on Express.js, designed
|
|
21
|
-
|
|
22
|
-
It is **TypeScript-first**, file-based, auto-discovers routes and middlewares, and provides a clean development experience.
|
|
18
|
+
Fastay is a modern backend framework built on Express.js, designed for fast, predictable, and developer-friendly API development. It is TypeScript-first, file-based, and automatically discovers routes and middlewares.
|
|
23
19
|
|
|
24
|
-
|
|
20
|
+
The complete documentation is available at:
|
|
25
21
|
|
|
26
|
-
|
|
27
|
-
- [Quick Start](#quick-start)
|
|
28
|
-
- [Project Structure](#project-structure)
|
|
29
|
-
- [Main Configuration](#main-configuration)
|
|
30
|
-
- [Routing System](#routing-system)
|
|
31
|
-
- [Middleware System](#middleware-system)
|
|
32
|
-
- [Comparison with Other Frameworks](#comparison-with-other-frameworks)
|
|
33
|
-
|
|
34
|
-
## Fastay Philosophy
|
|
35
|
-
|
|
36
|
-
### The Art of Intentional Simplicity
|
|
37
|
-
|
|
38
|
-
Fastay is born from an obsession with simplicity and speed, representing a minimalist approach to modern backend development. Our philosophy is based on principles that value efficiency without sacrificing power.
|
|
39
|
-
|
|
40
|
-
### Fundamental Principles
|
|
41
|
-
|
|
42
|
-
#### 1. Less is More
|
|
43
|
-
- We eliminate unnecessary layers that don't add real value
|
|
44
|
-
- Focus on what's essential to build robust APIs
|
|
45
|
-
- Zero architectural bureaucracy that drains time and energy
|
|
46
|
-
|
|
47
|
-
#### 2. Freedom with Structure
|
|
48
|
-
- We provide a solid foundation without imposing limitations
|
|
49
|
-
- You maintain full control over how your project evolves
|
|
50
|
-
- Flexibility to scale according to your specific needs
|
|
51
|
-
|
|
52
|
-
#### 3. Fluid Development
|
|
53
|
-
- Intuitive and frictionless development experience
|
|
54
|
-
- Minimal configuration, maximum results
|
|
55
|
-
- Focus on business logic, not complex configurations
|
|
56
|
-
|
|
57
|
-
### Who Fastay Was Created For
|
|
58
|
-
|
|
59
|
-
**Ideal for:**
|
|
60
|
-
- Developers who value simplicity and efficiency
|
|
61
|
-
- Teams that need development speed
|
|
62
|
-
- Projects requiring long-term maintainability
|
|
63
|
-
- Those who prefer explicit code over complex magic
|
|
64
|
-
|
|
65
|
-
**Perfect Use Cases:**
|
|
66
|
-
- Small to medium-sized RESTful APIs
|
|
67
|
-
- Quick prototypes and MVPs
|
|
68
|
-
- Lightweight microservices
|
|
69
|
-
- Projects where development speed is crucial
|
|
70
|
-
|
|
71
|
-
### The Perfect Balance
|
|
72
|
-
|
|
73
|
-
Fastay finds the sweet spot between:
|
|
74
|
-
|
|
75
|
-
**Express.js (too minimalist) ← FASTAY → NestJS (too structured)**
|
|
76
|
-
|
|
77
|
-
**Developer freedom ← FASTAY → Smart conventions**
|
|
78
|
-
|
|
79
|
-
**Total flexibility ← FASTAY → Maximum productivity**
|
|
80
|
-
|
|
81
|
-
### Technical Manifesto
|
|
82
|
-
|
|
83
|
-
"We believe that frameworks should facilitate and not complicate. That complexity should be added by choice, not imposed by default. That developers deserve tools that respect their time and intelligence."
|
|
84
|
-
|
|
85
|
-
Fastay is not just a framework - it's a statement of principles: that it's possible to have power without complexity, structure without rigidity, and conventions without dictatorship.
|
|
86
|
-
|
|
87
|
-
[⬆ Back to Top](#fastay-documentation)
|
|
22
|
+
[https://fastay.syntay.site](https://fastay.syntay.site)
|
|
88
23
|
|
|
89
24
|
## Quick Start
|
|
90
25
|
|
|
91
|
-
### 1. Create a New Project
|
|
92
|
-
|
|
93
26
|
```bash
|
|
94
27
|
npx fastay create-app my-app
|
|
95
|
-
```
|
|
96
|
-
|
|
97
|
-
Example CLI interaction:
|
|
98
|
-
|
|
99
|
-
```
|
|
100
|
-
Fastay — Create a modern backend project
|
|
101
|
-
✔ Use TypeScript? › Yes
|
|
102
|
-
✔ Choose an ORM: › None
|
|
103
|
-
```
|
|
104
|
-
|
|
105
|
-
### Navigate to the Project
|
|
106
|
-
|
|
107
|
-
```bash
|
|
108
28
|
cd my-app
|
|
109
|
-
```
|
|
110
|
-
|
|
111
|
-
### Start Development Server
|
|
112
|
-
|
|
113
|
-
```bash
|
|
114
29
|
npm run dev
|
|
115
30
|
```
|
|
116
31
|
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
```bash
|
|
120
|
-
npm run dev:watch
|
|
121
|
-
```
|
|
122
|
-
|
|
123
|
-
[⬆ Back to Top](#fastay-documentation)
|
|
124
|
-
|
|
125
|
-
## Project Structure
|
|
126
|
-
|
|
127
|
-
```
|
|
128
|
-
my-app/
|
|
129
|
-
│
|
|
130
|
-
├── dist/ # Compiled production code
|
|
131
|
-
├── src/
|
|
132
|
-
│ ├── api/ # API routes (auto-loaded)
|
|
133
|
-
│ │ ├── hello/
|
|
134
|
-
│ │ │ └── route.ts
|
|
135
|
-
│ │ ├── users/
|
|
136
|
-
│ │ │ └── route.ts
|
|
137
|
-
│ │ └── products/
|
|
138
|
-
│ │ └── route.ts
|
|
139
|
-
│ │
|
|
140
|
-
│ ├── middlewares/ # Fastay middlewares
|
|
141
|
-
│ │ ├── auth.ts
|
|
142
|
-
│ │ ├── logger.ts
|
|
143
|
-
│ │ └── middleware.ts
|
|
144
|
-
│ │
|
|
145
|
-
│ ├── services/ # Business logic (recommended)
|
|
146
|
-
│ │ ├── user-service.ts
|
|
147
|
-
│ │ └── product-service.ts
|
|
148
|
-
│ │
|
|
149
|
-
│ ├── utils/ # Helper functions
|
|
150
|
-
│ │ └── formatters.ts
|
|
151
|
-
│ │
|
|
152
|
-
│ └── index.ts # Application entry point
|
|
153
|
-
│
|
|
154
|
-
├── fastay.config.json # Global framework configuration
|
|
155
|
-
├── package.json
|
|
156
|
-
├── tsconfig.json
|
|
157
|
-
└── eslint.config.mjs
|
|
158
|
-
```
|
|
159
|
-
|
|
160
|
-
### Main Directories Description
|
|
161
|
-
|
|
162
|
-
- **src/api** - Each folder represents a route group. Every route.ts is automatically registered
|
|
163
|
-
- **src/middlewares** - Custom middlewares, automatically loaded
|
|
164
|
-
- **src/services** - Keeps business logic separate from routes
|
|
165
|
-
- **src/utils** - Helpers and utility functions
|
|
166
|
-
- **src/index.ts** - Main application bootstrap
|
|
167
|
-
- **dist/** - Compiled production code
|
|
168
|
-
- **fastay.config.json** - Build and compiler configuration
|
|
169
|
-
|
|
170
|
-
[⬆ Back to Top](#fastay-documentation)
|
|
171
|
-
|
|
172
|
-
## Main Configuration
|
|
173
|
-
|
|
174
|
-
### src/index.ts File
|
|
175
|
-
|
|
176
|
-
```typescript
|
|
177
|
-
import { createApp } from '@syntay/fastay';
|
|
178
|
-
|
|
179
|
-
const port = 5555;
|
|
180
|
-
|
|
181
|
-
void (async () => {
|
|
182
|
-
await createApp({
|
|
183
|
-
apiDir: './src/api',
|
|
184
|
-
baseRoute: '/api',
|
|
185
|
-
port: port
|
|
186
|
-
});
|
|
187
|
-
})();
|
|
188
|
-
```
|
|
189
|
-
|
|
190
|
-
### createApp Configuration
|
|
191
|
-
|
|
192
|
-
The createApp method is the heart of Fastay, responsible for initializing and configuring the entire application. It accepts a flexible configuration object that allows customization from routes to global middlewares.
|
|
193
|
-
|
|
194
|
-
### Configuration Parameters
|
|
195
|
-
|
|
196
|
-
#### Basic Parameters
|
|
197
|
-
|
|
198
|
-
```typescript
|
|
199
|
-
void (async () => {
|
|
200
|
-
await createApp({
|
|
201
|
-
// Server port (optional) - default: 5000
|
|
202
|
-
port: 5000,
|
|
203
|
-
// Routes directory (optional) - default: './src/api'
|
|
204
|
-
apiDir: './src/api',
|
|
205
|
-
// Base route (optional) - default: '/api'
|
|
206
|
-
baseRoute: '/api',
|
|
207
|
-
// Fastay middlewares (optional)
|
|
208
|
-
middlewares: {
|
|
209
|
-
'/api/hello': [home]
|
|
210
|
-
}
|
|
211
|
-
});
|
|
212
|
-
})();
|
|
213
|
-
```
|
|
214
|
-
|
|
215
|
-
#### Complete Practical Example
|
|
216
|
-
|
|
217
|
-
```typescript
|
|
218
|
-
import { createApp } from '@syntay/fastay';
|
|
219
|
-
import { home } from './middlewares/home';
|
|
220
|
-
|
|
221
|
-
void (async () => {
|
|
222
|
-
await createApp({
|
|
223
|
-
port: 5000,
|
|
224
|
-
apiDir: './src/api',
|
|
225
|
-
baseRoute: '/api',
|
|
226
|
-
middlewares: {
|
|
227
|
-
'/api/hello': [home] // Middleware applied only to /api/hello route
|
|
228
|
-
},
|
|
229
|
-
expressOptions: {
|
|
230
|
-
// Express configurations...
|
|
231
|
-
}
|
|
232
|
-
});
|
|
233
|
-
})();
|
|
234
|
-
```
|
|
235
|
-
|
|
236
|
-
### Express Configurations (expressOptions)
|
|
237
|
-
|
|
238
|
-
Since Fastay is built on Express, you can leverage all Express functionalities through the expressOptions object.
|
|
239
|
-
|
|
240
|
-
#### Global Middlewares
|
|
241
|
-
|
|
242
|
-
```typescript
|
|
243
|
-
expressOptions: {
|
|
244
|
-
middlewares: [
|
|
245
|
-
cors(),
|
|
246
|
-
helmet(),
|
|
247
|
-
(req, res, next) => {
|
|
248
|
-
res.setHeader('X-Powered-By', 'Fastay.js');
|
|
249
|
-
console.log("Global middleware executed");
|
|
250
|
-
next();
|
|
251
|
-
},
|
|
252
|
-
],
|
|
253
|
-
}
|
|
254
|
-
```
|
|
255
|
-
|
|
256
|
-
#### Body Parsers Configuration
|
|
257
|
-
|
|
258
|
-
```typescript
|
|
259
|
-
expressOptions: {
|
|
260
|
-
jsonOptions: {
|
|
261
|
-
limit: '10mb', // Size limit for JSON
|
|
262
|
-
strict: true // Only objects and arrays
|
|
263
|
-
},
|
|
264
|
-
urlencodedOptions: {
|
|
265
|
-
extended: true, // Allows complex objects
|
|
266
|
-
limit: '10mb' // Size limit
|
|
267
|
-
},
|
|
268
|
-
}
|
|
269
|
-
```
|
|
270
|
-
|
|
271
|
-
#### Serve Static Files
|
|
272
|
-
|
|
273
|
-
```typescript
|
|
274
|
-
expressOptions: {
|
|
275
|
-
static: {
|
|
276
|
-
path: "public", // Static files directory
|
|
277
|
-
options: {
|
|
278
|
-
maxAge: "1d", // 1 day cache
|
|
279
|
-
etag: true // Enable ETag
|
|
280
|
-
}
|
|
281
|
-
},
|
|
282
|
-
}
|
|
283
|
-
```
|
|
284
|
-
|
|
285
|
-
#### Template Engine Configuration
|
|
286
|
-
|
|
287
|
-
```typescript
|
|
288
|
-
expressOptions: {
|
|
289
|
-
views: {
|
|
290
|
-
engine: "pug", // Template engine (Pug, EJS, etc.)
|
|
291
|
-
dir: "views" // Views directory
|
|
292
|
-
},
|
|
293
|
-
}
|
|
294
|
-
```
|
|
295
|
-
|
|
296
|
-
#### Global Local Variables
|
|
297
|
-
|
|
298
|
-
```typescript
|
|
299
|
-
expressOptions: {
|
|
300
|
-
locals: {
|
|
301
|
-
appName: "My Fastay App",
|
|
302
|
-
version: "1.0.0",
|
|
303
|
-
author: "Your Team"
|
|
304
|
-
},
|
|
305
|
-
}
|
|
306
|
-
```
|
|
307
|
-
|
|
308
|
-
#### Reverse Proxy Configuration
|
|
309
|
-
|
|
310
|
-
```typescript
|
|
311
|
-
expressOptions: {
|
|
312
|
-
trustProxy: true, // Important for Nginx, Cloudflare, etc.
|
|
313
|
-
}
|
|
314
|
-
```
|
|
315
|
-
|
|
316
|
-
#### Custom Error Handler
|
|
317
|
-
|
|
318
|
-
```typescript
|
|
319
|
-
expressOptions: {
|
|
320
|
-
errorHandler: (err, req, res, next) => {
|
|
321
|
-
console.error('Error captured:', err);
|
|
322
|
-
if (err.statusCode) {
|
|
323
|
-
res.status(err.statusCode).json({
|
|
324
|
-
error: err.message,
|
|
325
|
-
code: err.code
|
|
326
|
-
});
|
|
327
|
-
} else {
|
|
328
|
-
res.status(500).json({
|
|
329
|
-
error: 'Internal server error',
|
|
330
|
-
code: 'INTERNAL_ERROR'
|
|
331
|
-
});
|
|
332
|
-
}
|
|
333
|
-
},
|
|
334
|
-
}
|
|
335
|
-
```
|
|
336
|
-
|
|
337
|
-
### CORS Configuration
|
|
338
|
-
|
|
339
|
-
Fastay offers a simplified and powerful CORS configuration:
|
|
340
|
-
|
|
341
|
-
#### Complete CORS Example
|
|
342
|
-
|
|
343
|
-
```typescript
|
|
344
|
-
expressOptions: {
|
|
345
|
-
enableCors: {
|
|
346
|
-
// Allow requests from any origin (be careful in production)
|
|
347
|
-
allowAnyOrigin: true,
|
|
348
|
-
// Specific URLs that can send cookies
|
|
349
|
-
cookieOrigins: [
|
|
350
|
-
'https://mysite.com',
|
|
351
|
-
'https://app.mysite.com',
|
|
352
|
-
'http://localhost:3000'
|
|
353
|
-
],
|
|
354
|
-
// Enable cross-origin cookie sending
|
|
355
|
-
credentials: true,
|
|
356
|
-
// Allowed HTTP methods
|
|
357
|
-
methods: 'GET,POST,PUT,DELETE,OPTIONS,PATCH,HEAD',
|
|
358
|
-
// Allowed request headers
|
|
359
|
-
headers: 'Content-Type, Authorization, X-Requested-With, X-Custom-Header',
|
|
360
|
-
// Headers exposed to client
|
|
361
|
-
exposedHeaders: 'X-Custom-Header, X-Total-Count',
|
|
362
|
-
// Preflight request cache time (24 hours)
|
|
363
|
-
maxAge: 86400,
|
|
364
|
-
},
|
|
365
|
-
}
|
|
366
|
-
```
|
|
367
|
-
|
|
368
|
-
#### Secure Production Configuration
|
|
369
|
-
|
|
370
|
-
```typescript
|
|
371
|
-
expressOptions: {
|
|
372
|
-
enableCors: {
|
|
373
|
-
allowAnyOrigin: false,
|
|
374
|
-
cookieOrigins: [
|
|
375
|
-
'https://mydomain.com',
|
|
376
|
-
'https://api.mydomain.com'
|
|
377
|
-
],
|
|
378
|
-
credentials: true,
|
|
379
|
-
methods: 'GET,POST,PUT,DELETE',
|
|
380
|
-
headers: 'Content-Type, Authorization',
|
|
381
|
-
maxAge: 3600, // 1 hour
|
|
382
|
-
},
|
|
383
|
-
}
|
|
384
|
-
```
|
|
385
|
-
|
|
386
|
-
#### Development Configuration
|
|
387
|
-
|
|
388
|
-
```typescript
|
|
389
|
-
expressOptions: {
|
|
390
|
-
enableCors: {
|
|
391
|
-
allowAnyOrigin: true, // Allow any origin in development
|
|
392
|
-
credentials: true,
|
|
393
|
-
methods: 'GET,POST,PUT,DELETE,OPTIONS,PATCH',
|
|
394
|
-
headers: '*', // Allow all headers
|
|
395
|
-
maxAge: 86400,
|
|
396
|
-
},
|
|
397
|
-
}
|
|
398
|
-
```
|
|
399
|
-
|
|
400
|
-
### Complete Configuration Example
|
|
401
|
-
|
|
402
|
-
```typescript
|
|
403
|
-
import { createApp } from '@syntay/fastay';
|
|
404
|
-
import cors from 'cors';
|
|
405
|
-
import helmet from 'helmet';
|
|
406
|
-
import { authMiddleware } from './middlewares/auth';
|
|
407
|
-
import { loggerMiddleware } from './middlewares/logger';
|
|
408
|
-
|
|
409
|
-
void (async () => {
|
|
410
|
-
await createApp({
|
|
411
|
-
// Basic configurations
|
|
412
|
-
port: process.env.PORT || 5000,
|
|
413
|
-
apiDir: './src/api',
|
|
414
|
-
baseRoute: '/api/v1',
|
|
415
|
-
|
|
416
|
-
// Fastay middlewares
|
|
417
|
-
middlewares: {
|
|
418
|
-
'/api/v1/admin': [authMiddleware, loggerMiddleware],
|
|
419
|
-
'/api/v1/users': [authMiddleware],
|
|
420
|
-
},
|
|
421
|
-
|
|
422
|
-
// Express configurations
|
|
423
|
-
expressOptions: {
|
|
424
|
-
// Global middlewares
|
|
425
|
-
middlewares: [
|
|
426
|
-
helmet(),
|
|
427
|
-
(req, res, next) => {
|
|
428
|
-
console.log(`${new Date().toISOString()} - ${req.method} ${req.path}`);
|
|
429
|
-
next();
|
|
430
|
-
}
|
|
431
|
-
],
|
|
432
|
-
|
|
433
|
-
// CORS configuration
|
|
434
|
-
enableCors: {
|
|
435
|
-
allowAnyOrigin: process.env.NODE_ENV === 'development',
|
|
436
|
-
cookieOrigins: [
|
|
437
|
-
'https://mysite.com',
|
|
438
|
-
'https://app.mysite.com'
|
|
439
|
-
],
|
|
440
|
-
credentials: true,
|
|
441
|
-
methods: 'GET,POST,PUT,DELETE,OPTIONS',
|
|
442
|
-
headers: 'Content-Type, Authorization, X-API-Key',
|
|
443
|
-
maxAge: 86400,
|
|
444
|
-
},
|
|
445
|
-
|
|
446
|
-
// Body parsers
|
|
447
|
-
jsonOptions: {
|
|
448
|
-
limit: '10mb'
|
|
449
|
-
},
|
|
450
|
-
urlencodedOptions: {
|
|
451
|
-
extended: true
|
|
452
|
-
},
|
|
453
|
-
|
|
454
|
-
// Static files
|
|
455
|
-
static: {
|
|
456
|
-
path: "public",
|
|
457
|
-
options: {
|
|
458
|
-
maxAge: 3600000
|
|
459
|
-
}
|
|
460
|
-
},
|
|
461
|
-
|
|
462
|
-
// Template engine
|
|
463
|
-
views: {
|
|
464
|
-
engine: "ejs",
|
|
465
|
-
dir: "src/views"
|
|
466
|
-
},
|
|
467
|
-
|
|
468
|
-
// Local variables
|
|
469
|
-
locals: {
|
|
470
|
-
appName: "My API",
|
|
471
|
-
environment: process.env.NODE_ENV || 'development'
|
|
472
|
-
},
|
|
473
|
-
|
|
474
|
-
// Reverse proxy
|
|
475
|
-
trustProxy: true,
|
|
476
|
-
|
|
477
|
-
// Custom error handler
|
|
478
|
-
errorHandler: (err, req, res, next) => {
|
|
479
|
-
const isProduction = process.env.NODE_ENV === 'production';
|
|
480
|
-
res.status(err.status || 500).json({
|
|
481
|
-
error: isProduction ? 'Something went wrong' : err.message,
|
|
482
|
-
...(!isProduction && { stack: err.stack })
|
|
483
|
-
});
|
|
484
|
-
}
|
|
485
|
-
}
|
|
486
|
-
});
|
|
487
|
-
})();
|
|
488
|
-
```
|
|
489
|
-
|
|
490
|
-
### Important Tips
|
|
491
|
-
|
|
492
|
-
#### Middleware Order
|
|
493
|
-
|
|
494
|
-
```typescript
|
|
495
|
-
// Order matters! Following the flow:
|
|
496
|
-
expressOptions: {
|
|
497
|
-
middlewares: [
|
|
498
|
-
helmet(), // 1. Security first
|
|
499
|
-
cors(), // 2. CORS before body parsers
|
|
500
|
-
express.json(), // 3. Body parsers
|
|
501
|
-
express.urlencoded(),
|
|
502
|
-
logger, // 4. Logging
|
|
503
|
-
auth // 5. Authentication
|
|
504
|
-
],
|
|
505
|
-
}
|
|
506
|
-
```
|
|
507
|
-
|
|
508
|
-
#### Environment-based Configuration
|
|
509
|
-
|
|
510
|
-
```typescript
|
|
511
|
-
const isDevelopment = process.env.NODE_ENV === 'development';
|
|
512
|
-
|
|
513
|
-
await createApp({
|
|
514
|
-
port: process.env.PORT || 5000,
|
|
515
|
-
expressOptions: {
|
|
516
|
-
enableCors: {
|
|
517
|
-
allowAnyOrigin: isDevelopment, // Only allowed in development
|
|
518
|
-
credentials: !isDevelopment, // Cookies only in production
|
|
519
|
-
},
|
|
520
|
-
trustProxy: !isDevelopment, // Proxy only in production
|
|
521
|
-
}
|
|
522
|
-
});
|
|
523
|
-
```
|
|
524
|
-
|
|
525
|
-
#### Specific vs Global Middlewares
|
|
526
|
-
|
|
527
|
-
```typescript
|
|
528
|
-
await createApp({
|
|
529
|
-
// Specific route middlewares (Fastay)
|
|
530
|
-
middlewares: {
|
|
531
|
-
'/api/admin': [adminAuth, adminLogger], // Only for /api/admin
|
|
532
|
-
'/api/public': [rateLimit], // Only for /api/public
|
|
533
|
-
},
|
|
534
|
-
expressOptions: {
|
|
535
|
-
// Global middlewares (Express)
|
|
536
|
-
middlewares: [
|
|
537
|
-
cors(), // For all routes
|
|
538
|
-
helmet(), // For all routes
|
|
539
|
-
],
|
|
540
|
-
}
|
|
541
|
-
});
|
|
542
|
-
```
|
|
543
|
-
|
|
544
|
-
### Security Considerations
|
|
545
|
-
|
|
546
|
-
- **CORS in Production**: Never use `allowAnyOrigin: true` in production
|
|
547
|
-
- **Body Parser Limits**: Set reasonable limits to prevent attacks
|
|
548
|
-
- **Helmet**: Always include Helmet for basic security
|
|
549
|
-
- **Trust Proxy**: Configure correctly to avoid IP issues
|
|
550
|
-
|
|
551
|
-
[⬆ Back to Top](#fastay-documentation)
|
|
552
|
-
|
|
553
|
-
## Routing System
|
|
554
|
-
|
|
555
|
-
Fastay uses a file-based routing system that combines simplicity with power. Routes are self-discoverable and intuitively organized.
|
|
556
|
-
|
|
557
|
-
### API Folder Structure
|
|
558
|
-
|
|
559
|
-
In Fastay.js, API routes are placed inside the directory defined in apiDir (default: './src/api'). Each subfolder represents an API endpoint.
|
|
560
|
-
|
|
561
|
-
```
|
|
562
|
-
src/
|
|
563
|
-
├── api/
|
|
564
|
-
│ ├── hello/
|
|
565
|
-
│ │ └── route.ts # → /api/hello
|
|
566
|
-
│ ├── users/
|
|
567
|
-
│ │ └── route.ts # → /api/users
|
|
568
|
-
│ └── products/
|
|
569
|
-
│ └── route.ts # → /api/products
|
|
570
|
-
```
|
|
571
|
-
|
|
572
|
-
### Basic Route Definition
|
|
573
|
-
|
|
574
|
-
#### Clean and Intuitive Syntax
|
|
575
|
-
|
|
576
|
-
```typescript
|
|
577
|
-
import { Request } from '@syntay/fastay';
|
|
578
|
-
|
|
579
|
-
// GET /api/hello
|
|
580
|
-
export async function GET() {
|
|
581
|
-
return "Hello World";
|
|
582
|
-
}
|
|
583
|
-
|
|
584
|
-
// POST /api/hello
|
|
585
|
-
export async function POST(req: Request) {
|
|
586
|
-
return { message: 'Hello World' };
|
|
587
|
-
}
|
|
588
|
-
```
|
|
589
|
-
|
|
590
|
-
**Routing System Characteristics:**
|
|
591
|
-
- ✅ Each HTTP method is exported as a function
|
|
592
|
-
- ✅ Automatically registered by Fastay
|
|
593
|
-
- ✅ Fully typed and TypeScript compatible
|
|
594
|
-
- ✅ Supports native Express middlewares
|
|
595
|
-
|
|
596
|
-
### Supported HTTP Methods
|
|
597
|
-
|
|
598
|
-
You can handle all main HTTP methods in the same route file:
|
|
599
|
-
|
|
600
|
-
```typescript
|
|
601
|
-
// api/users/route.ts
|
|
602
|
-
import { Request } from '@syntay/fastay';
|
|
603
|
-
|
|
604
|
-
// GET /api/users
|
|
605
|
-
export async function GET() {
|
|
606
|
-
const users = [
|
|
607
|
-
{ id: 1, name: 'John' },
|
|
608
|
-
{ id: 2, name: 'Mary' }
|
|
609
|
-
];
|
|
610
|
-
return users;
|
|
611
|
-
}
|
|
612
|
-
|
|
613
|
-
// POST /api/users
|
|
614
|
-
export async function POST(req: Request) {
|
|
615
|
-
const userData = await req.body;
|
|
616
|
-
// Save user to database
|
|
617
|
-
return { message: 'User created successfully', user: userData };
|
|
618
|
-
}
|
|
619
|
-
|
|
620
|
-
// PUT /api/users
|
|
621
|
-
export async function PUT(req: Request) {
|
|
622
|
-
const userData = await req.body;
|
|
623
|
-
// Update user
|
|
624
|
-
return { message: 'User updated', user: userData };
|
|
625
|
-
}
|
|
626
|
-
|
|
627
|
-
// DELETE /api/users
|
|
628
|
-
export async function DELETE(req: Request) {
|
|
629
|
-
// Delete user
|
|
630
|
-
return { message: 'User deleted' };
|
|
631
|
-
}
|
|
632
|
-
|
|
633
|
-
// PATCH /api/users
|
|
634
|
-
export async function PATCH(req: Request) {
|
|
635
|
-
const updates = await req.body;
|
|
636
|
-
// Partial update
|
|
637
|
-
return { message: 'User partially updated', updates };
|
|
638
|
-
}
|
|
639
|
-
```
|
|
640
|
-
|
|
641
|
-
### Advanced Response System
|
|
642
|
-
|
|
643
|
-
Fastay offers a flexible system for building HTTP responses with different content types.
|
|
644
|
-
|
|
645
|
-
#### JSON Response (Default)
|
|
646
|
-
|
|
647
|
-
```typescript
|
|
648
|
-
export async function GET() {
|
|
649
|
-
return {
|
|
650
|
-
success: true,
|
|
651
|
-
data: { id: 1, name: 'John' }
|
|
652
|
-
};
|
|
653
|
-
}
|
|
654
|
-
```
|
|
655
|
-
|
|
656
|
-
#### STRING Response
|
|
657
|
-
|
|
658
|
-
```typescript
|
|
659
|
-
export async function GET() {
|
|
660
|
-
return 'John Doe'
|
|
661
|
-
}
|
|
662
|
-
```
|
|
663
|
-
|
|
664
|
-
#### NUMBER Response
|
|
665
|
-
|
|
666
|
-
```typescript
|
|
667
|
-
export async function GET() {
|
|
668
|
-
return 1975
|
|
669
|
-
}
|
|
670
|
-
```
|
|
671
|
-
|
|
672
|
-
#### Response with Custom Status Code
|
|
673
|
-
|
|
674
|
-
```typescript
|
|
675
|
-
export async function POST(req: Request) {
|
|
676
|
-
const data = await req.body;
|
|
677
|
-
return {
|
|
678
|
-
status: 201, // Created
|
|
679
|
-
body: {
|
|
680
|
-
message: 'Resource created successfully',
|
|
681
|
-
data
|
|
682
|
-
}
|
|
683
|
-
};
|
|
684
|
-
}
|
|
685
|
-
```
|
|
686
|
-
|
|
687
|
-
#### Response with Cookies
|
|
688
|
-
|
|
689
|
-
```typescript
|
|
690
|
-
export async function POST(req: Request) {
|
|
691
|
-
const token = 'jwt_token_here';
|
|
692
|
-
const cookies = {
|
|
693
|
-
user_token: {
|
|
694
|
-
value: token,
|
|
695
|
-
options: {
|
|
696
|
-
httpOnly: true,
|
|
697
|
-
secure: process.env.NODE_ENV === 'production',
|
|
698
|
-
path: '/',
|
|
699
|
-
sameSite: process.env.NODE_ENV === 'production' ? 'none' : 'lax',
|
|
700
|
-
domain: process.env.NODE_ENV === 'production' ? 'yoursite.com' : 'localhost',
|
|
701
|
-
maxAge: 30 * 24 * 60 * 60 * 1000, // 30 days
|
|
702
|
-
},
|
|
703
|
-
},
|
|
704
|
-
};
|
|
705
|
-
|
|
706
|
-
return {
|
|
707
|
-
cookies,
|
|
708
|
-
status: 200,
|
|
709
|
-
body: {
|
|
710
|
-
message: "User registered successfully"
|
|
711
|
-
}
|
|
712
|
-
};
|
|
713
|
-
}
|
|
714
|
-
```
|
|
715
|
-
|
|
716
|
-
#### Response with Custom Headers
|
|
717
|
-
|
|
718
|
-
```typescript
|
|
719
|
-
export async function GET() {
|
|
720
|
-
return {
|
|
721
|
-
headers: {
|
|
722
|
-
'Content-Type': 'application/json',
|
|
723
|
-
'X-Custom-Header': 'custom-value',
|
|
724
|
-
'Cache-Control': 'no-cache'
|
|
725
|
-
},
|
|
726
|
-
body: {
|
|
727
|
-
data: 'content'
|
|
728
|
-
}
|
|
729
|
-
};
|
|
730
|
-
}
|
|
731
|
-
```
|
|
732
|
-
|
|
733
|
-
#### Redirection
|
|
734
|
-
|
|
735
|
-
```typescript
|
|
736
|
-
export async function GET() {
|
|
737
|
-
// Temporary redirection (302)
|
|
738
|
-
return {
|
|
739
|
-
redirect: '/new-route',
|
|
740
|
-
status: 302
|
|
741
|
-
};
|
|
742
|
-
}
|
|
743
|
-
|
|
744
|
-
export async function POST() {
|
|
745
|
-
// Permanent redirection (301)
|
|
746
|
-
return {
|
|
747
|
-
redirect: 'https://example.com',
|
|
748
|
-
status: 301
|
|
749
|
-
};
|
|
750
|
-
}
|
|
751
|
-
```
|
|
752
|
-
|
|
753
|
-
#### File Download
|
|
754
|
-
|
|
755
|
-
```typescript
|
|
756
|
-
export async function GET() {
|
|
757
|
-
return {
|
|
758
|
-
file: {
|
|
759
|
-
path: '/path/to/report.pdf',
|
|
760
|
-
downloadName: 'monthly-report.pdf'
|
|
761
|
-
}
|
|
762
|
-
};
|
|
763
|
-
}
|
|
764
|
-
```
|
|
765
|
-
|
|
766
|
-
#### Data Stream
|
|
767
|
-
|
|
768
|
-
```typescript
|
|
769
|
-
import fs from 'fs';
|
|
770
|
-
|
|
771
|
-
export async function GET() {
|
|
772
|
-
return {
|
|
773
|
-
stream: fs.createReadStream('/videos/movie.mp4'),
|
|
774
|
-
headers: {
|
|
775
|
-
'Content-Type': 'video/mp4'
|
|
776
|
-
}
|
|
777
|
-
};
|
|
778
|
-
}
|
|
779
|
-
```
|
|
780
|
-
|
|
781
|
-
#### Raw Response (Buffer/String)
|
|
32
|
+
## Why Fastay?
|
|
782
33
|
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
headers: {
|
|
788
|
-
'Content-Type': 'text/plain'
|
|
789
|
-
}
|
|
790
|
-
};
|
|
791
|
-
}
|
|
792
|
-
```
|
|
793
|
-
|
|
794
|
-
### Dynamic Routes
|
|
795
|
-
|
|
796
|
-
#### URL Parameters
|
|
797
|
-
|
|
798
|
-
```typescript
|
|
799
|
-
// api/users/[id]/route.ts
|
|
800
|
-
import { Request } from '@syntay/fastay';
|
|
801
|
-
|
|
802
|
-
export async function GET(req: Request) {
|
|
803
|
-
const { id } = req.params;
|
|
804
|
-
// Find user by ID
|
|
805
|
-
return {
|
|
806
|
-
message: `User details with ID: ${id}`,
|
|
807
|
-
user: { id, name: `User ${id}` }
|
|
808
|
-
};
|
|
809
|
-
}
|
|
810
|
-
```
|
|
811
|
-
|
|
812
|
-
**Access:** `GET /api/users/123` → `{ id: '123' }`
|
|
813
|
-
|
|
814
|
-
#### Query Parameters
|
|
815
|
-
|
|
816
|
-
```typescript
|
|
817
|
-
// api/users/route.ts
|
|
818
|
-
import { Request } from '@syntay/fastay';
|
|
819
|
-
|
|
820
|
-
interface UserQuery {
|
|
821
|
-
name?: string;
|
|
822
|
-
email?: string;
|
|
823
|
-
page?: number;
|
|
824
|
-
}
|
|
825
|
-
|
|
826
|
-
export async function GET(req: Request) {
|
|
827
|
-
const query: UserQuery = req.query;
|
|
828
|
-
const { name, email, page = 1 } = query;
|
|
829
|
-
|
|
830
|
-
// Find users with filters
|
|
831
|
-
return {
|
|
832
|
-
users: [
|
|
833
|
-
{ id: 1, name, email },
|
|
834
|
-
{ id: 2, name: 'Mary', email: 'mary@email.com' }
|
|
835
|
-
],
|
|
836
|
-
pagination: {
|
|
837
|
-
page,
|
|
838
|
-
totalPages: 5
|
|
839
|
-
}
|
|
840
|
-
};
|
|
841
|
-
}
|
|
842
|
-
```
|
|
843
|
-
|
|
844
|
-
**Access:** `GET /api/users?name=John&email=john@email.com&page=2`
|
|
845
|
-
|
|
846
|
-
#### Combining Parameters and Query
|
|
847
|
-
|
|
848
|
-
```typescript
|
|
849
|
-
// api/users/[id]/posts/route.ts
|
|
850
|
-
import { Request } from '@syntay/fastay';
|
|
851
|
-
|
|
852
|
-
export async function GET(req: Request) {
|
|
853
|
-
const { id } = req.params; // User ID
|
|
854
|
-
const { category, limit = 10 } = req.query; // Filters
|
|
855
|
-
|
|
856
|
-
return {
|
|
857
|
-
userId: id,
|
|
858
|
-
posts: [
|
|
859
|
-
{ id: 1, title: 'Post 1', category },
|
|
860
|
-
{ id: 2, title: 'Post 2', category }
|
|
861
|
-
],
|
|
862
|
-
filters: { category, limit }
|
|
863
|
-
};
|
|
864
|
-
}
|
|
865
|
-
```
|
|
866
|
-
|
|
867
|
-
### Working with FormData
|
|
868
|
-
|
|
869
|
-
#### File Uploads and Forms
|
|
870
|
-
|
|
871
|
-
```typescript
|
|
872
|
-
// api/upload/route.ts
|
|
873
|
-
import { Request } from '@syntay/fastay';
|
|
874
|
-
|
|
875
|
-
export async function POST(req: Request) {
|
|
876
|
-
const formData = await req.formData();
|
|
877
|
-
const id = formData.get('id') as string;
|
|
878
|
-
const name = formData.get('name') as string;
|
|
879
|
-
const image = formData.get('image') as File;
|
|
880
|
-
|
|
881
|
-
// Process image upload
|
|
882
|
-
console.log('File received:', image.name, image.size);
|
|
883
|
-
|
|
884
|
-
return {
|
|
885
|
-
message: 'Upload completed successfully',
|
|
886
|
-
data: { id, name, fileName: image.name }
|
|
887
|
-
};
|
|
888
|
-
}
|
|
889
|
-
```
|
|
890
|
-
|
|
891
|
-
### Working with Cookies
|
|
892
|
-
|
|
893
|
-
#### Reading Cookies
|
|
894
|
-
|
|
895
|
-
```typescript
|
|
896
|
-
export async function GET(req: Request) {
|
|
897
|
-
// Check if cookie exists
|
|
898
|
-
if (req.cookies.has('user_token')) {
|
|
899
|
-
// Get cookie value
|
|
900
|
-
const token = req.cookies.get('user_token');
|
|
901
|
-
return {
|
|
902
|
-
authenticated: true,
|
|
903
|
-
user: { token }
|
|
904
|
-
};
|
|
905
|
-
}
|
|
906
|
-
|
|
907
|
-
return { authenticated: false };
|
|
908
|
-
}
|
|
909
|
-
```
|
|
910
|
-
|
|
911
|
-
#### Available Cookie Methods
|
|
912
|
-
|
|
913
|
-
```typescript
|
|
914
|
-
export async function GET(req: Request) {
|
|
915
|
-
// Check existence
|
|
916
|
-
const hasToken = req.cookies.has('user_token');
|
|
917
|
-
// Get value
|
|
918
|
-
const token = req.cookies.get('user_token');
|
|
919
|
-
// Get all cookies
|
|
920
|
-
const allCookies = req.cookies.all();
|
|
921
|
-
|
|
922
|
-
return {
|
|
923
|
-
cookieInfo: {
|
|
924
|
-
hasToken,
|
|
925
|
-
token,
|
|
926
|
-
allCookies
|
|
927
|
-
}
|
|
928
|
-
};
|
|
929
|
-
}
|
|
930
|
-
```
|
|
931
|
-
|
|
932
|
-
### Error Handling
|
|
933
|
-
|
|
934
|
-
#### Try/Catch Block
|
|
935
|
-
|
|
936
|
-
```typescript
|
|
937
|
-
export async function GET() {
|
|
938
|
-
try {
|
|
939
|
-
const data = await fetchExternalData();
|
|
940
|
-
return { data };
|
|
941
|
-
} catch (error) {
|
|
942
|
-
return {
|
|
943
|
-
status: 500,
|
|
944
|
-
body: {
|
|
945
|
-
error: 'Internal server error',
|
|
946
|
-
message: error.message
|
|
947
|
-
}
|
|
948
|
-
};
|
|
949
|
-
}
|
|
950
|
-
}
|
|
951
|
-
```
|
|
952
|
-
|
|
953
|
-
#### Errors with Specific Status Codes
|
|
954
|
-
|
|
955
|
-
```typescript
|
|
956
|
-
export async function GET(req: Request) {
|
|
957
|
-
const { id } = req.params;
|
|
958
|
-
const user = await findUserById(id);
|
|
959
|
-
|
|
960
|
-
if (!user) {
|
|
961
|
-
return {
|
|
962
|
-
status: 404,
|
|
963
|
-
body: { error: 'User not found' }
|
|
964
|
-
};
|
|
965
|
-
}
|
|
966
|
-
|
|
967
|
-
if (!user.active) {
|
|
968
|
-
return {
|
|
969
|
-
status: 403,
|
|
970
|
-
body: { error: 'User inactive' }
|
|
971
|
-
};
|
|
972
|
-
}
|
|
973
|
-
|
|
974
|
-
return { user };
|
|
975
|
-
}
|
|
976
|
-
```
|
|
977
|
-
|
|
978
|
-
#### Data Validation
|
|
979
|
-
|
|
980
|
-
```typescript
|
|
981
|
-
export async function POST(req: Request) {
|
|
982
|
-
const userData = await req.body;
|
|
983
|
-
|
|
984
|
-
// Simple validation
|
|
985
|
-
if (!userData.name || !userData.email) {
|
|
986
|
-
return {
|
|
987
|
-
status: 400,
|
|
988
|
-
body: {
|
|
989
|
-
error: 'Invalid data',
|
|
990
|
-
required: ['name', 'email']
|
|
991
|
-
}
|
|
992
|
-
};
|
|
993
|
-
}
|
|
994
|
-
|
|
995
|
-
// Process valid data
|
|
996
|
-
return {
|
|
997
|
-
status: 201,
|
|
998
|
-
body: {
|
|
999
|
-
message: 'User created',
|
|
1000
|
-
user: userData
|
|
1001
|
-
}
|
|
1002
|
-
};
|
|
1003
|
-
}
|
|
1004
|
-
```
|
|
1005
|
-
|
|
1006
|
-
### Complete Practical Examples
|
|
1007
|
-
|
|
1008
|
-
#### Complete Blog API
|
|
1009
|
-
|
|
1010
|
-
```typescript
|
|
1011
|
-
// api/posts/route.ts
|
|
1012
|
-
import { Request } from '@syntay/fastay';
|
|
1013
|
-
|
|
1014
|
-
// GET /api/posts - List posts with pagination
|
|
1015
|
-
export async function GET(req: Request) {
|
|
1016
|
-
const { page = 1, limit = 10, category } = req.query;
|
|
1017
|
-
const posts = await findPosts({
|
|
1018
|
-
page: parseInt(page),
|
|
1019
|
-
limit: parseInt(limit),
|
|
1020
|
-
category
|
|
1021
|
-
});
|
|
1022
|
-
|
|
1023
|
-
return {
|
|
1024
|
-
posts,
|
|
1025
|
-
pagination: {
|
|
1026
|
-
page,
|
|
1027
|
-
limit,
|
|
1028
|
-
total: posts.length
|
|
1029
|
-
}
|
|
1030
|
-
};
|
|
1031
|
-
}
|
|
1032
|
-
|
|
1033
|
-
// POST /api/posts - Create new post
|
|
1034
|
-
export async function POST(req: Request) {
|
|
1035
|
-
const postData = await req.body;
|
|
1036
|
-
|
|
1037
|
-
// Validation
|
|
1038
|
-
if (!postData.title || !postData.content) {
|
|
1039
|
-
return {
|
|
1040
|
-
status: 400,
|
|
1041
|
-
body: { error: 'Title and content are required' }
|
|
1042
|
-
};
|
|
1043
|
-
}
|
|
1044
|
-
|
|
1045
|
-
const newPost = await createPost(postData);
|
|
1046
|
-
return {
|
|
1047
|
-
status: 201,
|
|
1048
|
-
body: {
|
|
1049
|
-
message: 'Post created successfully',
|
|
1050
|
-
post: newPost
|
|
1051
|
-
}
|
|
1052
|
-
};
|
|
1053
|
-
}
|
|
1054
|
-
```
|
|
1055
|
-
|
|
1056
|
-
#### Authentication API
|
|
1057
|
-
|
|
1058
|
-
```typescript
|
|
1059
|
-
// api/auth/login/route.ts
|
|
1060
|
-
import { Request } from '@syntay/fastay';
|
|
1061
|
-
|
|
1062
|
-
export async function POST(req: Request) {
|
|
1063
|
-
const { email, password } = await req.body;
|
|
1064
|
-
|
|
1065
|
-
// Verify credentials
|
|
1066
|
-
const user = await verifyCredentials(email, password);
|
|
1067
|
-
if (!user) {
|
|
1068
|
-
return {
|
|
1069
|
-
status: 401,
|
|
1070
|
-
body: { error: 'Invalid credentials' }
|
|
1071
|
-
};
|
|
1072
|
-
}
|
|
1073
|
-
|
|
1074
|
-
// Generate token
|
|
1075
|
-
const token = generateJWTToken(user);
|
|
1076
|
-
|
|
1077
|
-
const cookies = {
|
|
1078
|
-
auth_token: {
|
|
1079
|
-
value: token,
|
|
1080
|
-
options: {
|
|
1081
|
-
httpOnly: true,
|
|
1082
|
-
secure: process.env.NODE_ENV === 'production',
|
|
1083
|
-
maxAge: 24 * 60 * 60 * 1000, // 24 hours
|
|
1084
|
-
path: '/'
|
|
1085
|
-
}
|
|
1086
|
-
}
|
|
1087
|
-
};
|
|
1088
|
-
|
|
1089
|
-
return {
|
|
1090
|
-
cookies,
|
|
1091
|
-
body: {
|
|
1092
|
-
message: 'Login successful',
|
|
1093
|
-
user: {
|
|
1094
|
-
id: user.id,
|
|
1095
|
-
name: user.name
|
|
1096
|
-
}
|
|
1097
|
-
}
|
|
1098
|
-
};
|
|
1099
|
-
}
|
|
1100
|
-
```
|
|
1101
|
-
|
|
1102
|
-
### Best Practices Tips
|
|
1103
|
-
|
|
1104
|
-
#### Route Organization
|
|
1105
|
-
|
|
1106
|
-
```
|
|
1107
|
-
src/api/
|
|
1108
|
-
├── users/
|
|
1109
|
-
│ ├── route.ts # Basic operations
|
|
1110
|
-
│ ├── [id]/
|
|
1111
|
-
│ │ └── route.ts # Operations by ID
|
|
1112
|
-
│ └── auth/
|
|
1113
|
-
│ └── route.ts # Authentication
|
|
1114
|
-
├── posts/
|
|
1115
|
-
│ ├── route.ts
|
|
1116
|
-
│ └── [id]/
|
|
1117
|
-
│ └── comments/
|
|
1118
|
-
│ └── route.ts # Post comments
|
|
1119
|
-
```
|
|
1120
|
-
|
|
1121
|
-
#### Consistent Validation
|
|
1122
|
-
|
|
1123
|
-
```typescript
|
|
1124
|
-
// utils/validation.ts
|
|
1125
|
-
export function validateUser(data: any) {
|
|
1126
|
-
const errors = [];
|
|
1127
|
-
if (!data.name) errors.push('Name is required');
|
|
1128
|
-
if (!data.email) errors.push('Email is required');
|
|
1129
|
-
if (!validateEmail(data.email)) errors.push('Invalid email');
|
|
1130
|
-
return errors;
|
|
1131
|
-
}
|
|
1132
|
-
|
|
1133
|
-
// api/users/route.ts
|
|
1134
|
-
export async function POST(req: Request) {
|
|
1135
|
-
const userData = await req.body;
|
|
1136
|
-
const errors = validateUser(userData);
|
|
1137
|
-
|
|
1138
|
-
if (errors.length > 0) {
|
|
1139
|
-
return {
|
|
1140
|
-
status: 400,
|
|
1141
|
-
body: { errors: errors }
|
|
1142
|
-
};
|
|
1143
|
-
}
|
|
1144
|
-
|
|
1145
|
-
// Process valid data...
|
|
1146
|
-
}
|
|
1147
|
-
```
|
|
1148
|
-
|
|
1149
|
-
#### Standardized Responses
|
|
1150
|
-
|
|
1151
|
-
```typescript
|
|
1152
|
-
// utils/response.ts
|
|
1153
|
-
export function success(data: any, message = 'Success') {
|
|
1154
|
-
return {
|
|
1155
|
-
status: 'success',
|
|
1156
|
-
message,
|
|
1157
|
-
data
|
|
1158
|
-
};
|
|
1159
|
-
}
|
|
1160
|
-
|
|
1161
|
-
export function error(message: string, code = 'ERROR') {
|
|
1162
|
-
return {
|
|
1163
|
-
status: 'error',
|
|
1164
|
-
message,
|
|
1165
|
-
code
|
|
1166
|
-
};
|
|
1167
|
-
}
|
|
1168
|
-
|
|
1169
|
-
// Usage in routes
|
|
1170
|
-
export async function GET() {
|
|
1171
|
-
try {
|
|
1172
|
-
const users = await findUsers();
|
|
1173
|
-
return success(users, 'Users listed successfully');
|
|
1174
|
-
} catch (err) {
|
|
1175
|
-
return error('Error fetching users');
|
|
1176
|
-
}
|
|
1177
|
-
}
|
|
1178
|
-
```
|
|
1179
|
-
|
|
1180
|
-
[⬆ Back to Top](#fastay-documentation)
|
|
1181
|
-
|
|
1182
|
-
## Middleware System
|
|
1183
|
-
|
|
1184
|
-
### Auto-loaded Middlewares
|
|
1185
|
-
|
|
1186
|
-
```typescript
|
|
1187
|
-
import { Request, Response, Next } from '@syntay/fastay';
|
|
1188
|
-
|
|
1189
|
-
export async function auth(req: Request, _res: Response, next: Next) {
|
|
1190
|
-
// Authentication logic
|
|
1191
|
-
next();
|
|
1192
|
-
}
|
|
1193
|
-
```
|
|
1194
|
-
|
|
1195
|
-
### Middleware Configuration in Fastay.js
|
|
1196
|
-
|
|
1197
|
-
In Fastay.js, middlewares are used to intercept and process requests before they reach the defined routes. They work as "intermediate functions" that can perform actions like authentication, data validation, logging, among others, and are executed in the defined sequence until the request reaches the final route.
|
|
1198
|
-
|
|
1199
|
-
#### Execution Flow
|
|
1200
|
-
|
|
1201
|
-
```
|
|
1202
|
-
Request → Middleware 1 → Middleware 2 → ... → Final Route → Response
|
|
1203
|
-
```
|
|
1204
|
-
|
|
1205
|
-
### Basic Structure
|
|
1206
|
-
|
|
1207
|
-
#### Recommended File Structure
|
|
1208
|
-
|
|
1209
|
-
```
|
|
1210
|
-
src/
|
|
1211
|
-
├── middlewares/
|
|
1212
|
-
│ ├── auth.ts # Authentication middleware
|
|
1213
|
-
│ ├── validation.ts # Validation middleware
|
|
1214
|
-
│ ├── logger.ts # Logging middleware
|
|
1215
|
-
│ └── middleware.ts # Main configuration
|
|
1216
|
-
```
|
|
1217
|
-
|
|
1218
|
-
### Configuration
|
|
1219
|
-
|
|
1220
|
-
#### createMiddleware Method
|
|
1221
|
-
|
|
1222
|
-
The createMiddleware method allows associating middlewares with specific routes:
|
|
1223
|
-
|
|
1224
|
-
```typescript
|
|
1225
|
-
export const middleware = createMiddleware({
|
|
1226
|
-
// Syntax: [route]: [array-of-middlewares]
|
|
1227
|
-
'/api/specific-route': [middleware1, middleware2],
|
|
1228
|
-
// Multiple routes
|
|
1229
|
-
'/api/users': [auth],
|
|
1230
|
-
'/api/posts': [auth, logger],
|
|
1231
|
-
'/api/public': [logger],
|
|
1232
|
-
});
|
|
1233
|
-
```
|
|
1234
|
-
|
|
1235
|
-
### Defining Middlewares in Fastay.js
|
|
1236
|
-
|
|
1237
|
-
Middlewares in Fastay.js are defined by convention in a directory called middlewares. Inside this directory, you create a middleware.ts (or middleware.js) file, where you can associate each middleware with a specific route.
|
|
1238
|
-
|
|
1239
|
-
#### middleware.ts File Example
|
|
1240
|
-
|
|
1241
|
-
The middleware.ts file is responsible for loading and applying middlewares to specific routes.
|
|
1242
|
-
|
|
1243
|
-
```typescript
|
|
1244
|
-
// src/middlewares/middleware.ts
|
|
1245
|
-
import { createMiddleware } from '@syntay/fastay';
|
|
1246
|
-
import { user } from './user';
|
|
1247
|
-
import { home } from './home';
|
|
1248
|
-
|
|
1249
|
-
// Here, you define the routes and middlewares that will be executed before each route
|
|
1250
|
-
export const middleware = createMiddleware({
|
|
1251
|
-
'/api/users': [user], // User middleware will be applied to /api/users route
|
|
1252
|
-
'/api/hello': [home], // Home middleware will be applied to /api/hello route
|
|
1253
|
-
});
|
|
1254
|
-
```
|
|
1255
|
-
|
|
1256
|
-
- **Route (/api/users)**: The specific route where the middleware will be executed. This allows you to associate middlewares with specific routes.
|
|
1257
|
-
- **Array of Middlewares ([user])**: An array of middlewares that will be executed before the route execution. There can be multiple middlewares in an array, and they will be executed in the order they are defined.
|
|
1258
|
-
|
|
1259
|
-
### Middleware Structure
|
|
1260
|
-
|
|
1261
|
-
A middleware in Fastay.js is basically an asynchronous function that receives three parameters: request, response, and next. The next() is used to indicate that the middleware has finished its execution and that the request can continue to the next middleware or to the target route.
|
|
1262
|
-
|
|
1263
|
-
#### user.ts Middleware Example
|
|
1264
|
-
|
|
1265
|
-
```typescript
|
|
1266
|
-
// src/middlewares/user.ts
|
|
1267
|
-
import { Next, Request, Response } from '@syntay/fastay';
|
|
1268
|
-
|
|
1269
|
-
export async function user(request: Request, _response: Response, next: Next) {
|
|
1270
|
-
console.log('User middleware executed');
|
|
1271
|
-
// Middleware logic, such as authentication or validation
|
|
1272
|
-
// Call the next middleware or route
|
|
1273
|
-
next();
|
|
1274
|
-
}
|
|
1275
|
-
```
|
|
1276
|
-
|
|
1277
|
-
- **request**: The request object containing the request data.
|
|
1278
|
-
- **response**: The response object, which allows manipulating the response before sending it to the client.
|
|
1279
|
-
- **next()**: Calls the next function in the middleware chain or the target route. If you don't call next(), the request will be "stuck" and won't proceed to the next middleware or route.
|
|
1280
|
-
|
|
1281
|
-
### Middleware Behavior
|
|
1282
|
-
|
|
1283
|
-
- **Sequential Execution**: Middlewares are executed sequentially. If you have multiple middlewares for the same route, they will be called in the order they are defined in the array.
|
|
1284
|
-
- **Execution Interruption**: If any middleware doesn't call next() or returns a response, the execution will be interrupted and the request won't proceed to the next middleware or route.
|
|
1285
|
-
|
|
1286
|
-
#### Execution Order
|
|
1287
|
-
|
|
1288
|
-
```typescript
|
|
1289
|
-
export const middleware = createMiddleware({
|
|
1290
|
-
'/api/protected': [
|
|
1291
|
-
middleware1, // Executed first
|
|
1292
|
-
middleware2, // Executed second
|
|
1293
|
-
middleware3 // Executed third
|
|
1294
|
-
],
|
|
1295
|
-
});
|
|
1296
|
-
```
|
|
1297
|
-
|
|
1298
|
-
#### Validation Middleware Example
|
|
1299
|
-
|
|
1300
|
-
```typescript
|
|
1301
|
-
// src/middlewares/validate.ts
|
|
1302
|
-
import { Next, Request, Response } from '@syntay/fastay';
|
|
1303
|
-
|
|
1304
|
-
export async function validate(request: Request, response: Response, next: Next) {
|
|
1305
|
-
if (!request.headers['authorization']) {
|
|
1306
|
-
response.status(400).json({ error: 'Missing authorization header' });
|
|
1307
|
-
} else {
|
|
1308
|
-
next(); // If validation passes, call next middleware or route
|
|
1309
|
-
}
|
|
1310
|
-
}
|
|
1311
|
-
```
|
|
1312
|
-
|
|
1313
|
-
### Caution with Heavy Processing
|
|
1314
|
-
|
|
1315
|
-
It's important to remember that middlewares should not be used for heavy tasks, such as processing large file uploads, database interactions, or complex calculations. The purpose of middlewares is to be lightweight and fast, with tasks like authentication, validation, or logging, and not for high computational cost operations.
|
|
1316
|
-
|
|
1317
|
-
### Complete Middleware Example in Fastay.js
|
|
34
|
+
- File-based routing with auto-discovery
|
|
35
|
+
- Clean separation between routes and middlewares
|
|
36
|
+
- Minimal configuration, maximum productivity
|
|
37
|
+
- Ideal for REST APIs, microservices, and MVPs
|
|
1318
38
|
|
|
1319
|
-
|
|
39
|
+
## Contributing
|
|
1320
40
|
|
|
1321
|
-
|
|
1322
|
-
src/
|
|
1323
|
-
middlewares/
|
|
1324
|
-
home.ts
|
|
1325
|
-
user.ts
|
|
1326
|
-
middleware.ts
|
|
1327
|
-
```
|
|
1328
|
-
|
|
1329
|
-
#### middleware.ts
|
|
1330
|
-
|
|
1331
|
-
```typescript
|
|
1332
|
-
import { createMiddleware } from '@syntay/fastay';
|
|
1333
|
-
import { user } from './user';
|
|
1334
|
-
import { home } from './home';
|
|
1335
|
-
|
|
1336
|
-
export const middleware = createMiddleware({
|
|
1337
|
-
'/api/users': [user], // User middleware for /api/users
|
|
1338
|
-
'/api/hello': [home], // Home middleware for /api/hello
|
|
1339
|
-
});
|
|
1340
|
-
```
|
|
1341
|
-
|
|
1342
|
-
#### user.ts (Authentication Middleware)
|
|
1343
|
-
|
|
1344
|
-
```typescript
|
|
1345
|
-
import { Next, Request, Response } from '@syntay/fastay';
|
|
1346
|
-
|
|
1347
|
-
export async function user(request: Request, _response: Response, next: Next) {
|
|
1348
|
-
console.log('User middleware executed');
|
|
1349
|
-
|
|
1350
|
-
// Simulated authentication token validation
|
|
1351
|
-
if (!request.headers['authorization']) {
|
|
1352
|
-
return _response.status(401).json({ error: 'Unauthorized' });
|
|
1353
|
-
}
|
|
1354
|
-
|
|
1355
|
-
// If everything is correct, call next middleware or route
|
|
1356
|
-
next();
|
|
1357
|
-
}
|
|
1358
|
-
```
|
|
1359
|
-
|
|
1360
|
-
#### home.ts (Logging Middleware)
|
|
1361
|
-
|
|
1362
|
-
```typescript
|
|
1363
|
-
import { Next, Request, Response } from '@syntay/fastay';
|
|
1364
|
-
|
|
1365
|
-
export async function home(request: Request, _response: Response, next: Next) {
|
|
1366
|
-
console.log('Home middleware executed');
|
|
1367
|
-
// Add logging logic here
|
|
1368
|
-
// Call next middleware or route
|
|
1369
|
-
next();
|
|
1370
|
-
}
|
|
1371
|
-
```
|
|
1372
|
-
|
|
1373
|
-
This example provides a complete explanation of how to configure and use middlewares in Fastay.js, with ready-to-copy code examples to apply in your project.
|
|
1374
|
-
|
|
1375
|
-
[⬆ Back to Top](#fastay-documentation)
|
|
1376
|
-
|
|
1377
|
-
## Comparison with Other Frameworks
|
|
1378
|
-
|
|
1379
|
-
### Pure Express.js
|
|
1380
|
-
|
|
1381
|
-
```typescript
|
|
1382
|
-
import express from 'express';
|
|
1383
|
-
const app = express();
|
|
1384
|
-
|
|
1385
|
-
// GET
|
|
1386
|
-
app.get('/api/hello', (req, res) => {
|
|
1387
|
-
res.json({ message: 'Hello World' });
|
|
1388
|
-
});
|
|
1389
|
-
|
|
1390
|
-
// POST
|
|
1391
|
-
app.post('/api/hello', (req, res) => {
|
|
1392
|
-
res.json({ message: 'Hello POST World' });
|
|
1393
|
-
});
|
|
1394
|
-
|
|
1395
|
-
app.listen(5000, () => console.log('Server running on port 5000'));
|
|
1396
|
-
```
|
|
1397
|
-
|
|
1398
|
-
**Disadvantages of pure Express:**
|
|
1399
|
-
- ❌ Manual registration of each route
|
|
1400
|
-
- ❌ Middleware and routes mixed together
|
|
1401
|
-
- ❌ Complicated scalability in large projects
|
|
1402
|
-
|
|
1403
|
-
### NestJS
|
|
1404
|
-
|
|
1405
|
-
```typescript
|
|
1406
|
-
import { Controller, Get, Post, Body } from '@nestjs/common';
|
|
1407
|
-
|
|
1408
|
-
@Controller('api/hello')
|
|
1409
|
-
export class HelloController {
|
|
1410
|
-
@Get()
|
|
1411
|
-
getHello() {
|
|
1412
|
-
return { message: 'Hello World' };
|
|
1413
|
-
}
|
|
1414
|
-
|
|
1415
|
-
@Post()
|
|
1416
|
-
postHello(@Body() body: any) {
|
|
1417
|
-
return { message: 'Hello POST World', body };
|
|
1418
|
-
}
|
|
1419
|
-
}
|
|
1420
|
-
```
|
|
1421
|
-
|
|
1422
|
-
**NestJS Characteristics:**
|
|
1423
|
-
- ✅ Based on decorators and classes
|
|
1424
|
-
- ✅ Module organization
|
|
1425
|
-
- ✅ Type-safe and TypeScript
|
|
1426
|
-
- ⚠️ Learning curve with decorators and DI
|
|
1427
|
-
|
|
1428
|
-
### Fastay.js
|
|
1429
|
-
|
|
1430
|
-
```typescript
|
|
1431
|
-
import { Request } from '@syntay/fastay';
|
|
1432
|
-
|
|
1433
|
-
// GET /api/hello
|
|
1434
|
-
export async function GET() {
|
|
1435
|
-
return { message: 'Hello World' };
|
|
1436
|
-
}
|
|
1437
|
-
|
|
1438
|
-
// POST /api/hello
|
|
1439
|
-
export async function POST(req: Request) {
|
|
1440
|
-
return { message: 'Hello POST World' };
|
|
1441
|
-
}
|
|
1442
|
-
```
|
|
1443
|
-
|
|
1444
|
-
**Fastay Advantages:**
|
|
1445
|
-
- ✅ File-based - each HTTP method is exported
|
|
1446
|
-
- ✅ Auto-discovered routes - no manual registration
|
|
1447
|
-
- ✅ Separate and organized middleware
|
|
1448
|
-
- ✅ Type-safe, clean and simple
|
|
1449
|
-
|
|
1450
|
-
### Request Flow
|
|
1451
|
-
|
|
1452
|
-
```
|
|
1453
|
-
Client → Fastay Route → Middleware → Route Handler → Service → Response
|
|
1454
|
-
```
|
|
1455
|
-
|
|
1456
|
-
## Contribution
|
|
1457
|
-
|
|
1458
|
-
Contributions are welcome! Follow the steps:
|
|
1459
|
-
|
|
1460
|
-
1. Fork the project
|
|
41
|
+
1. Fork the repository
|
|
1461
42
|
2. Create a branch (`git checkout -b my-feature`)
|
|
1462
|
-
3. Commit your changes (`git commit -
|
|
1463
|
-
4. Push to
|
|
43
|
+
3. Commit your changes (`git commit -m "Add feature"`)
|
|
44
|
+
4. Push to your branch
|
|
1464
45
|
5. Open a Pull Request
|
|
1465
46
|
|
|
1466
47
|
## License
|
|
1467
48
|
|
|
1468
49
|
MIT © Syntay Team
|
|
1469
|
-
|
|
1470
|
-
[⬆ Back to Top](#fastay-documentation)
|