balda-js 0.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/.github/workflows/publish.yml +38 -0
- package/.husky/pre-commit +19 -0
- package/.nvmrc +1 -0
- package/LICENSE +21 -0
- package/README.md +46 -0
- package/deno.lock +2454 -0
- package/docs/README.md +135 -0
- package/docs/blog/authors.yml +6 -0
- package/docs/blog/tags.yml +4 -0
- package/docs/cli.md +109 -0
- package/docs/docs/core-concepts/controllers.md +393 -0
- package/docs/docs/core-concepts/middleware.md +302 -0
- package/docs/docs/core-concepts/request-response.md +486 -0
- package/docs/docs/core-concepts/routing.md +388 -0
- package/docs/docs/core-concepts/server.md +332 -0
- package/docs/docs/cron/overview.md +70 -0
- package/docs/docs/examples/rest-api.md +595 -0
- package/docs/docs/getting-started/configuration.md +168 -0
- package/docs/docs/getting-started/installation.md +125 -0
- package/docs/docs/getting-started/quick-start.md +273 -0
- package/docs/docs/intro.md +46 -0
- package/docs/docs/plugins/cookie.md +424 -0
- package/docs/docs/plugins/cors.md +295 -0
- package/docs/docs/plugins/file.md +382 -0
- package/docs/docs/plugins/helmet.md +388 -0
- package/docs/docs/plugins/json.md +338 -0
- package/docs/docs/plugins/log.md +592 -0
- package/docs/docs/plugins/overview.md +390 -0
- package/docs/docs/plugins/rate-limiter.md +347 -0
- package/docs/docs/plugins/static.md +352 -0
- package/docs/docs/plugins/swagger.md +411 -0
- package/docs/docs/plugins/urlencoded.md +76 -0
- package/docs/docs/testing/examples.md +384 -0
- package/docs/docs/testing/mock-server.md +311 -0
- package/docs/docs/testing/overview.md +76 -0
- package/docs/docusaurus.config.ts +144 -0
- package/docs/intro.md +78 -0
- package/docs/package.json +46 -0
- package/docs/sidebars.ts +72 -0
- package/docs/static/.nojekyll +0 -0
- package/docs/static/img/docusaurus-social-card.jpg +0 -0
- package/docs/static/img/docusaurus.png +0 -0
- package/docs/static/img/favicon.ico +0 -0
- package/docs/static/img/logo.svg +1 -0
- package/docs/static/img/undraw_docusaurus_mountain.svg +37 -0
- package/docs/static/img/undraw_docusaurus_react.svg +170 -0
- package/docs/static/img/undraw_docusaurus_tree.svg +40 -0
- package/docs/tsconfig.json +8 -0
- package/package.json +91 -0
- package/speed_test.sh +3 -0
- package/test/benchmark/index.ts +17 -0
- package/test/cli/cli.ts +7 -0
- package/test/commands/test.ts +42 -0
- package/test/controllers/file_upload.ts +29 -0
- package/test/controllers/urlencoded.ts +13 -0
- package/test/controllers/users.ts +111 -0
- package/test/cron/index.ts +6 -0
- package/test/cron/test_cron.ts +8 -0
- package/test/cron/test_cron_imported.ts +8 -0
- package/test/native_env.ts +16 -0
- package/test/resources/test.txt +1 -0
- package/test/server/index.ts +3 -0
- package/test/server/instance.ts +63 -0
- package/test/suite/upload.test.ts +23 -0
- package/test/suite/urlencoded.test.ts +23 -0
- package/test/suite/users.test.ts +76 -0
- package/todo.md +9 -0
- package/tsconfig.json +24 -0
- package/vitest.config.ts +17 -0
@@ -0,0 +1,388 @@
|
|
1
|
+
---
|
2
|
+
sidebar_position: 3
|
3
|
+
---
|
4
|
+
|
5
|
+
# Routing
|
6
|
+
|
7
|
+
Balda.js provides a flexible and intuitive routing system that supports both direct route registration and controller-based routing with decorators.
|
8
|
+
|
9
|
+
## Route Registration
|
10
|
+
|
11
|
+
### Direct Route Registration
|
12
|
+
|
13
|
+
You can register routes directly on the server instance:
|
14
|
+
|
15
|
+
```typescript
|
16
|
+
import { Server } from 'balda-js';
|
17
|
+
|
18
|
+
const server = new Server({ port: 3000 });
|
19
|
+
|
20
|
+
// GET route
|
21
|
+
server.get('/users', (req, res) => {
|
22
|
+
res.json({ users: [] });
|
23
|
+
});
|
24
|
+
|
25
|
+
// POST route
|
26
|
+
server.post('/users', (req, res) => {
|
27
|
+
res.created(req.body);
|
28
|
+
});
|
29
|
+
|
30
|
+
// PUT route
|
31
|
+
server.put('/users/:id', (req, res) => {
|
32
|
+
res.json({ id: req.params.id, ...req.body });
|
33
|
+
});
|
34
|
+
|
35
|
+
// PATCH route
|
36
|
+
server.patch('/users/:id', (req, res) => {
|
37
|
+
res.json({ id: req.params.id, ...req.body });
|
38
|
+
});
|
39
|
+
|
40
|
+
// DELETE route
|
41
|
+
server.delete('/users/:id', (req, res) => {
|
42
|
+
res.noContent();
|
43
|
+
});
|
44
|
+
```
|
45
|
+
|
46
|
+
### Controller-Based Routing
|
47
|
+
|
48
|
+
Controllers provide a more organized way to define routes:
|
49
|
+
|
50
|
+
```typescript
|
51
|
+
import { controller, get, post, put, del } from 'balda-js';
|
52
|
+
|
53
|
+
@controller('/users')
|
54
|
+
export class UsersController {
|
55
|
+
@get('/')
|
56
|
+
async getAllUsers(req, res) {
|
57
|
+
res.json({ users: [] });
|
58
|
+
}
|
59
|
+
|
60
|
+
@get('/:id')
|
61
|
+
async getUserById(req, res) {
|
62
|
+
res.json({ id: req.params.id });
|
63
|
+
}
|
64
|
+
|
65
|
+
@post('/')
|
66
|
+
async createUser(req, res) {
|
67
|
+
res.created(req.body);
|
68
|
+
}
|
69
|
+
|
70
|
+
@put('/:id')
|
71
|
+
async updateUser(req, res) {
|
72
|
+
res.json({ id: req.params.id, ...req.body });
|
73
|
+
}
|
74
|
+
|
75
|
+
@del('/:id')
|
76
|
+
async deleteUser(req, res) {
|
77
|
+
res.noContent();
|
78
|
+
}
|
79
|
+
}
|
80
|
+
```
|
81
|
+
|
82
|
+
## Route Parameters
|
83
|
+
|
84
|
+
### Path Parameters
|
85
|
+
|
86
|
+
Define dynamic segments in your routes:
|
87
|
+
|
88
|
+
```typescript
|
89
|
+
@controller('/users')
|
90
|
+
export class UsersController {
|
91
|
+
@get('/:id')
|
92
|
+
async getUserById(req, res) {
|
93
|
+
const id = req.params.id;
|
94
|
+
res.json({ id });
|
95
|
+
}
|
96
|
+
|
97
|
+
@get('/:userId/posts/:postId')
|
98
|
+
async getUserPost(req, res) {
|
99
|
+
const { userId, postId } = req.params;
|
100
|
+
res.json({ userId, postId });
|
101
|
+
}
|
102
|
+
}
|
103
|
+
```
|
104
|
+
|
105
|
+
### Query Parameters
|
106
|
+
|
107
|
+
Access query string parameters:
|
108
|
+
|
109
|
+
```typescript
|
110
|
+
@get('/users')
|
111
|
+
async getUsers(req, res) {
|
112
|
+
const { page = 1, limit = 10, search } = req.query;
|
113
|
+
|
114
|
+
// Handle pagination and search
|
115
|
+
res.json({
|
116
|
+
page: parseInt(page),
|
117
|
+
limit: parseInt(limit),
|
118
|
+
search
|
119
|
+
});
|
120
|
+
}
|
121
|
+
```
|
122
|
+
|
123
|
+
## Route Options
|
124
|
+
|
125
|
+
### Middleware
|
126
|
+
|
127
|
+
Apply middleware to specific routes:
|
128
|
+
|
129
|
+
```typescript
|
130
|
+
@get('/admin/users', { middleware: [authMiddleware, adminMiddleware] })
|
131
|
+
async getAdminUsers(req, res) {
|
132
|
+
res.json({ users: [] });
|
133
|
+
}
|
134
|
+
```
|
135
|
+
|
136
|
+
### Swagger Documentation
|
137
|
+
|
138
|
+
Add OpenAPI documentation to routes:
|
139
|
+
|
140
|
+
```typescript
|
141
|
+
@get('/', {
|
142
|
+
swagger: {
|
143
|
+
summary: 'Get all users',
|
144
|
+
description: 'Retrieve a list of all users with pagination',
|
145
|
+
tags: ['Users'],
|
146
|
+
responses: {
|
147
|
+
200: {
|
148
|
+
description: 'List of users',
|
149
|
+
content: {
|
150
|
+
'application/json': {
|
151
|
+
schema: {
|
152
|
+
type: 'array',
|
153
|
+
items: { $ref: '#/components/schemas/User' }
|
154
|
+
}
|
155
|
+
}
|
156
|
+
}
|
157
|
+
}
|
158
|
+
}
|
159
|
+
}
|
160
|
+
})
|
161
|
+
async getAllUsers(req, res) {
|
162
|
+
res.json({ users: [] });
|
163
|
+
}
|
164
|
+
```
|
165
|
+
|
166
|
+
## Route Patterns
|
167
|
+
|
168
|
+
### Static Routes
|
169
|
+
|
170
|
+
```typescript
|
171
|
+
@get('/about')
|
172
|
+
async getAbout(req, res) {
|
173
|
+
res.json({ message: 'About page' });
|
174
|
+
}
|
175
|
+
```
|
176
|
+
|
177
|
+
### Dynamic Routes
|
178
|
+
|
179
|
+
```typescript
|
180
|
+
@get('/users/:id')
|
181
|
+
async getUser(req, res) {
|
182
|
+
const id = req.params.id;
|
183
|
+
res.json({ id });
|
184
|
+
}
|
185
|
+
```
|
186
|
+
|
187
|
+
### Optional Parameters
|
188
|
+
|
189
|
+
```typescript
|
190
|
+
@get('/posts/:id?')
|
191
|
+
async getPost(req, res) {
|
192
|
+
const id = req.params.id;
|
193
|
+
if (id) {
|
194
|
+
res.json({ id });
|
195
|
+
} else {
|
196
|
+
res.json({ posts: [] });
|
197
|
+
}
|
198
|
+
}
|
199
|
+
```
|
200
|
+
|
201
|
+
### Wildcard Routes
|
202
|
+
|
203
|
+
```typescript
|
204
|
+
@get('/files/*')
|
205
|
+
async getFile(req, res) {
|
206
|
+
const filePath = req.params['*'];
|
207
|
+
res.json({ filePath });
|
208
|
+
}
|
209
|
+
```
|
210
|
+
|
211
|
+
## Route Precedence
|
212
|
+
|
213
|
+
Routes are matched in the order they are registered. More specific routes should be defined before more general ones:
|
214
|
+
|
215
|
+
```typescript
|
216
|
+
@controller('/users')
|
217
|
+
export class UsersController {
|
218
|
+
// Specific route first
|
219
|
+
@get('/admin')
|
220
|
+
async getAdminUsers(req, res) {
|
221
|
+
res.json({ users: [] });
|
222
|
+
}
|
223
|
+
|
224
|
+
// General route after
|
225
|
+
@get('/:id')
|
226
|
+
async getUserById(req, res) {
|
227
|
+
res.json({ id: req.params.id });
|
228
|
+
}
|
229
|
+
}
|
230
|
+
```
|
231
|
+
|
232
|
+
## Route Groups
|
233
|
+
|
234
|
+
Organize related routes using controllers:
|
235
|
+
|
236
|
+
```typescript
|
237
|
+
@controller('/api/v1/users')
|
238
|
+
export class UsersController {
|
239
|
+
@get('/')
|
240
|
+
async getAllUsers(req, res) {
|
241
|
+
res.json({ users: [] });
|
242
|
+
}
|
243
|
+
}
|
244
|
+
|
245
|
+
@controller('/api/v1/posts')
|
246
|
+
export class PostsController {
|
247
|
+
@get('/')
|
248
|
+
async getAllPosts(req, res) {
|
249
|
+
res.json({ posts: [] });
|
250
|
+
}
|
251
|
+
}
|
252
|
+
```
|
253
|
+
|
254
|
+
## Error Handling
|
255
|
+
|
256
|
+
### 404 Not Found
|
257
|
+
|
258
|
+
Routes that don't match any pattern return a 404 response:
|
259
|
+
|
260
|
+
```typescript
|
261
|
+
// This will be handled by the 404 handler
|
262
|
+
server.get('/nonexistent', (req, res) => {
|
263
|
+
// This won't be reached
|
264
|
+
});
|
265
|
+
```
|
266
|
+
|
267
|
+
### Custom 404 Handler
|
268
|
+
|
269
|
+
```typescript
|
270
|
+
server.setErrorHandler((req, res, next, error) => {
|
271
|
+
if (error.name === 'RouteNotFoundError') {
|
272
|
+
return res.notFound({
|
273
|
+
error: 'Route not found',
|
274
|
+
path: req.url
|
275
|
+
});
|
276
|
+
}
|
277
|
+
next(error);
|
278
|
+
});
|
279
|
+
```
|
280
|
+
|
281
|
+
## Route Testing
|
282
|
+
|
283
|
+
### Mock Server
|
284
|
+
|
285
|
+
Use the mock server for testing routes:
|
286
|
+
|
287
|
+
```typescript
|
288
|
+
import { Server } from 'balda-js';
|
289
|
+
|
290
|
+
const server = new Server({ port: 3000 });
|
291
|
+
|
292
|
+
server.get('/users', (req, res) => {
|
293
|
+
res.json({ users: [] });
|
294
|
+
});
|
295
|
+
|
296
|
+
// Get mock server for testing
|
297
|
+
const mockServer = await server.getMockServer();
|
298
|
+
|
299
|
+
// Test the route
|
300
|
+
const response = await mockServer.get('/users');
|
301
|
+
console.log(response.statusCode()); // 200
|
302
|
+
console.log(response.body()); // { users: [] }
|
303
|
+
```
|
304
|
+
|
305
|
+
## Best Practices
|
306
|
+
|
307
|
+
### 1. Use Controllers for Organization
|
308
|
+
|
309
|
+
```typescript
|
310
|
+
// Good: Organized by resource
|
311
|
+
@controller('/users')
|
312
|
+
export class UsersController {}
|
313
|
+
|
314
|
+
@controller('/posts')
|
315
|
+
export class PostsController {}
|
316
|
+
|
317
|
+
// Avoid: Mixed resources in one controller
|
318
|
+
@controller('/api')
|
319
|
+
export class ApiController {} // Too broad
|
320
|
+
```
|
321
|
+
|
322
|
+
### 2. Consistent Naming
|
323
|
+
|
324
|
+
```typescript
|
325
|
+
// Good: RESTful naming
|
326
|
+
@get('/users') // GET /users
|
327
|
+
@get('/users/:id') // GET /users/123
|
328
|
+
@post('/users') // POST /users
|
329
|
+
@put('/users/:id') // PUT /users/123
|
330
|
+
@del('/users/:id') // DELETE /users/123
|
331
|
+
|
332
|
+
// Avoid: Inconsistent naming
|
333
|
+
@get('/getUsers')
|
334
|
+
@post('/createUser')
|
335
|
+
@put('/updateUser')
|
336
|
+
```
|
337
|
+
|
338
|
+
### 3. Parameter Validation
|
339
|
+
|
340
|
+
```typescript
|
341
|
+
@get('/users/:id')
|
342
|
+
async getUserById(req, res) {
|
343
|
+
const id = parseInt(req.params.id);
|
344
|
+
|
345
|
+
if (isNaN(id)) {
|
346
|
+
return res.badRequest({ error: 'Invalid user ID' });
|
347
|
+
}
|
348
|
+
|
349
|
+
res.json({ id });
|
350
|
+
}
|
351
|
+
```
|
352
|
+
|
353
|
+
### 4. Query Parameter Handling
|
354
|
+
|
355
|
+
```typescript
|
356
|
+
@get('/users')
|
357
|
+
async getUsers(req, res) {
|
358
|
+
const page = Math.max(1, parseInt(req.query.page) || 1);
|
359
|
+
const limit = Math.min(100, Math.max(1, parseInt(req.query.limit) || 10));
|
360
|
+
|
361
|
+
res.json({ page, limit });
|
362
|
+
}
|
363
|
+
```
|
364
|
+
|
365
|
+
### 5. Route Documentation
|
366
|
+
|
367
|
+
```typescript
|
368
|
+
@get('/', {
|
369
|
+
swagger: {
|
370
|
+
summary: 'Get all users',
|
371
|
+
description: 'Retrieve a paginated list of users',
|
372
|
+
tags: ['Users'],
|
373
|
+
parameters: [
|
374
|
+
{
|
375
|
+
name: 'page',
|
376
|
+
in: 'query',
|
377
|
+
description: 'Page number',
|
378
|
+
schema: { type: 'integer', default: 1 }
|
379
|
+
}
|
380
|
+
]
|
381
|
+
}
|
382
|
+
})
|
383
|
+
async getAllUsers(req, res) {
|
384
|
+
res.json({ users: [] });
|
385
|
+
}
|
386
|
+
```
|
387
|
+
|
388
|
+
Balda.js routing provides a powerful and flexible system for defining your application's endpoints with support for both simple and complex routing patterns.
|
@@ -0,0 +1,332 @@
|
|
1
|
+
---
|
2
|
+
sidebar_position: 1
|
3
|
+
---
|
4
|
+
|
5
|
+
# Server
|
6
|
+
|
7
|
+
The `Server` class is the main entry point for creating Balda.js applications. It handles HTTP requests, manages middleware, and orchestrates the entire application lifecycle.
|
8
|
+
|
9
|
+
## Creating a Server
|
10
|
+
|
11
|
+
```typescript
|
12
|
+
import { Server } from 'balda-js';
|
13
|
+
|
14
|
+
const server = new Server({
|
15
|
+
port: 3000,
|
16
|
+
host: 'localhost'
|
17
|
+
});
|
18
|
+
```
|
19
|
+
|
20
|
+
## Server Lifecycle
|
21
|
+
|
22
|
+
### 1. Initialization
|
23
|
+
|
24
|
+
When you create a server instance, it:
|
25
|
+
|
26
|
+
- Sets up the runtime connector (Node.js, Bun, or Deno)
|
27
|
+
- Initializes the router
|
28
|
+
- Applies global middleware
|
29
|
+
- Sets up the body parser
|
30
|
+
|
31
|
+
```typescript
|
32
|
+
const server = new Server({
|
33
|
+
port: 3000,
|
34
|
+
plugins: {
|
35
|
+
cors: { origin: '*' },
|
36
|
+
json: { sizeLimit: '1mb' }
|
37
|
+
}
|
38
|
+
});
|
39
|
+
```
|
40
|
+
|
41
|
+
### 2. Route Registration
|
42
|
+
|
43
|
+
Routes can be registered in two ways:
|
44
|
+
|
45
|
+
**Direct registration:**
|
46
|
+
```typescript
|
47
|
+
server.get('/users', (req, res) => {
|
48
|
+
res.json({ users: [] });
|
49
|
+
});
|
50
|
+
```
|
51
|
+
|
52
|
+
**Controller-based registration:**
|
53
|
+
```typescript
|
54
|
+
@controller('/users')
|
55
|
+
export class UsersController {
|
56
|
+
@get('/')
|
57
|
+
async getUsers(req, res) {
|
58
|
+
res.json({ users: [] });
|
59
|
+
}
|
60
|
+
}
|
61
|
+
```
|
62
|
+
|
63
|
+
### 3. Server Startup
|
64
|
+
|
65
|
+
When you call `server.listen()`, the server:
|
66
|
+
|
67
|
+
- Imports controllers based on patterns
|
68
|
+
- Registers all routes
|
69
|
+
- Applies plugins
|
70
|
+
- Starts listening for requests
|
71
|
+
|
72
|
+
```typescript
|
73
|
+
server.listen(({ port, host }) => {
|
74
|
+
console.log(`Server running on http://${host}:${port}`);
|
75
|
+
});
|
76
|
+
```
|
77
|
+
|
78
|
+
## Server Configuration
|
79
|
+
|
80
|
+
### Basic Options
|
81
|
+
|
82
|
+
```typescript
|
83
|
+
const server = new Server({
|
84
|
+
port: 3000, // Server port
|
85
|
+
host: 'localhost', // Server host
|
86
|
+
controllerPatterns: [ // Controller file patterns
|
87
|
+
'./controllers/**/*.ts'
|
88
|
+
],
|
89
|
+
plugins: {}, // Plugin configuration
|
90
|
+
swagger: true, // Enable Swagger docs
|
91
|
+
tapOptions: {} // Runtime-specific options
|
92
|
+
});
|
93
|
+
```
|
94
|
+
|
95
|
+
### Advanced Configuration
|
96
|
+
|
97
|
+
```typescript
|
98
|
+
const server = new Server({
|
99
|
+
port: process.env.PORT || 3000,
|
100
|
+
host: process.env.HOST || '0.0.0.0',
|
101
|
+
controllerPatterns: [
|
102
|
+
'./src/controllers/**/*.ts',
|
103
|
+
'./src/api/**/*.ts'
|
104
|
+
],
|
105
|
+
plugins: {
|
106
|
+
cors: { origin: '*' },
|
107
|
+
json: { sizeLimit: '10mb' },
|
108
|
+
static: { root: './public' }
|
109
|
+
},
|
110
|
+
swagger: {
|
111
|
+
type: 'standard',
|
112
|
+
models: {
|
113
|
+
User: {
|
114
|
+
type: 'object',
|
115
|
+
properties: {
|
116
|
+
id: { type: 'number' },
|
117
|
+
name: { type: 'string' }
|
118
|
+
}
|
119
|
+
}
|
120
|
+
}
|
121
|
+
}
|
122
|
+
});
|
123
|
+
```
|
124
|
+
|
125
|
+
## Server Methods
|
126
|
+
|
127
|
+
### HTTP Methods
|
128
|
+
|
129
|
+
```typescript
|
130
|
+
// GET requests
|
131
|
+
server.get('/users', (req, res) => {
|
132
|
+
res.json({ users: [] });
|
133
|
+
});
|
134
|
+
|
135
|
+
// POST requests
|
136
|
+
server.post('/users', (req, res) => {
|
137
|
+
res.created({ id: 1, name: 'John' });
|
138
|
+
});
|
139
|
+
|
140
|
+
// PUT requests
|
141
|
+
server.put('/users/:id', (req, res) => {
|
142
|
+
res.json({ id: req.params.id, name: 'Updated' });
|
143
|
+
});
|
144
|
+
|
145
|
+
// PATCH requests
|
146
|
+
server.patch('/users/:id', (req, res) => {
|
147
|
+
res.json({ id: req.params.id, ...req.body });
|
148
|
+
});
|
149
|
+
|
150
|
+
// DELETE requests
|
151
|
+
server.delete('/users/:id', (req, res) => {
|
152
|
+
res.noContent();
|
153
|
+
});
|
154
|
+
```
|
155
|
+
|
156
|
+
### Middleware Management
|
157
|
+
|
158
|
+
```typescript
|
159
|
+
// Add global middleware
|
160
|
+
server.use((req, res, next) => {
|
161
|
+
console.log(`${req.method} ${req.url}`);
|
162
|
+
next();
|
163
|
+
});
|
164
|
+
|
165
|
+
// Add multiple middleware
|
166
|
+
server.use(
|
167
|
+
(req, res, next) => {
|
168
|
+
req.startTime = Date.now();
|
169
|
+
next();
|
170
|
+
},
|
171
|
+
(req, res, next) => {
|
172
|
+
res.on('finish', () => {
|
173
|
+
const duration = Date.now() - req.startTime;
|
174
|
+
console.log(`${req.method} ${req.url} - ${duration}ms`);
|
175
|
+
});
|
176
|
+
next();
|
177
|
+
}
|
178
|
+
);
|
179
|
+
```
|
180
|
+
|
181
|
+
### Error Handling
|
182
|
+
|
183
|
+
```typescript
|
184
|
+
server.setErrorHandler((req, res, next, error) => {
|
185
|
+
console.error('Error:', error);
|
186
|
+
|
187
|
+
if (error.name === 'ValidationError') {
|
188
|
+
return res.badRequest({ error: error.message });
|
189
|
+
}
|
190
|
+
|
191
|
+
res.internalServerError({ error: 'Internal server error' });
|
192
|
+
});
|
193
|
+
```
|
194
|
+
|
195
|
+
## Server Properties
|
196
|
+
|
197
|
+
### Read-only Properties
|
198
|
+
|
199
|
+
```typescript
|
200
|
+
// Get server URL
|
201
|
+
console.log(server.url); // http://localhost:3000
|
202
|
+
|
203
|
+
// Get server port
|
204
|
+
console.log(server.port); // 3000
|
205
|
+
|
206
|
+
// Get server host
|
207
|
+
console.log(server.host); // localhost
|
208
|
+
|
209
|
+
// Check if server is listening
|
210
|
+
console.log(server.isListening); // true/false
|
211
|
+
```
|
212
|
+
|
213
|
+
### Utility Methods
|
214
|
+
|
215
|
+
```typescript
|
216
|
+
// Get temporary directory
|
217
|
+
const tmpDir = server.tmpDir('uploads', 'images');
|
218
|
+
|
219
|
+
// Embed data for later use
|
220
|
+
server.embed('config', { apiKey: 'secret' });
|
221
|
+
|
222
|
+
// Get embedded data
|
223
|
+
const config = server.embed('config');
|
224
|
+
|
225
|
+
// Exit the server
|
226
|
+
server.exit(0);
|
227
|
+
```
|
228
|
+
|
229
|
+
## Event Handling
|
230
|
+
|
231
|
+
```typescript
|
232
|
+
// Handle graceful shutdown
|
233
|
+
server.on('SIGTERM', () => {
|
234
|
+
console.log('Received SIGTERM, shutting down gracefully');
|
235
|
+
server.close();
|
236
|
+
});
|
237
|
+
|
238
|
+
server.on('SIGINT', () => {
|
239
|
+
console.log('Received SIGINT, shutting down gracefully');
|
240
|
+
server.close();
|
241
|
+
});
|
242
|
+
```
|
243
|
+
|
244
|
+
## Server Shutdown
|
245
|
+
|
246
|
+
```typescript
|
247
|
+
// Graceful shutdown
|
248
|
+
async function shutdown() {
|
249
|
+
console.log('Shutting down server...');
|
250
|
+
await server.close();
|
251
|
+
console.log('Server shut down successfully');
|
252
|
+
process.exit(0);
|
253
|
+
}
|
254
|
+
|
255
|
+
// Handle shutdown signals
|
256
|
+
process.on('SIGTERM', shutdown);
|
257
|
+
process.on('SIGINT', shutdown);
|
258
|
+
```
|
259
|
+
|
260
|
+
## Runtime Support
|
261
|
+
|
262
|
+
Balda.js automatically detects and adapts to your runtime:
|
263
|
+
|
264
|
+
### Node.js
|
265
|
+
```typescript
|
266
|
+
// Uses Node.js http module
|
267
|
+
const server = new Server({
|
268
|
+
port: 3000
|
269
|
+
});
|
270
|
+
```
|
271
|
+
|
272
|
+
### Bun
|
273
|
+
```typescript
|
274
|
+
// Uses Bun's HTTP server
|
275
|
+
const server = new Server({
|
276
|
+
port: 3000
|
277
|
+
});
|
278
|
+
```
|
279
|
+
|
280
|
+
### Deno
|
281
|
+
```typescript
|
282
|
+
// Uses Deno's HTTP server
|
283
|
+
const server = new Server({
|
284
|
+
port: 3000
|
285
|
+
});
|
286
|
+
```
|
287
|
+
|
288
|
+
## Complete Example
|
289
|
+
|
290
|
+
```typescript
|
291
|
+
import { Server } from 'balda-js';
|
292
|
+
|
293
|
+
const server = new Server({
|
294
|
+
port: 3000,
|
295
|
+
host: 'localhost',
|
296
|
+
controllerPatterns: ['./src/controllers/**/*.ts'],
|
297
|
+
plugins: {
|
298
|
+
cors: { origin: '*' },
|
299
|
+
json: { sizeLimit: '10mb' },
|
300
|
+
log: { logRequest: true }
|
301
|
+
}
|
302
|
+
});
|
303
|
+
|
304
|
+
// Global middleware
|
305
|
+
server.use((req, res, next) => {
|
306
|
+
req.startTime = Date.now();
|
307
|
+
next();
|
308
|
+
});
|
309
|
+
|
310
|
+
// Error handler
|
311
|
+
server.setErrorHandler((req, res, next, error) => {
|
312
|
+
console.error('Error:', error);
|
313
|
+
res.internalServerError({ error: 'Something went wrong' });
|
314
|
+
});
|
315
|
+
|
316
|
+
// Direct route registration
|
317
|
+
server.get('/health', (req, res) => {
|
318
|
+
res.json({ status: 'ok', uptime: process.uptime() });
|
319
|
+
});
|
320
|
+
|
321
|
+
// Start server
|
322
|
+
server.listen(({ port, host }) => {
|
323
|
+
console.log(`🚀 Server running on http://${host}:${port}`);
|
324
|
+
console.log(`📚 API Documentation: http://${host}:${port}/docs`);
|
325
|
+
});
|
326
|
+
|
327
|
+
// Graceful shutdown
|
328
|
+
process.on('SIGTERM', () => server.close());
|
329
|
+
process.on('SIGINT', () => server.close());
|
330
|
+
```
|
331
|
+
|
332
|
+
The Server class provides a solid foundation for building scalable web applications with Balda.js.
|