turbo-express-js 1.0.7 → 1.0.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,466 @@
1
+ # TurboServer - A Fast and Powerful Node.js Web Server Framework
2
+
3
+ TurboServer is inspired by Express.js
4
+ and offers a similar API to make it easy for developers familiar with Express to get started.
5
+ In fact, TurboServer offers many of the same features and middleware that Express does,
6
+ making it a great choice for developers who want a fast and efficient alternative to Express.
7
+
8
+ > Made with ❤️ by Mike Karypidis
9
+
10
+ #
11
+
12
+ Additionally, TurboServer is built with an OOP architecture in mind,
13
+ with Request and Response classes acting as interfaces.
14
+ This makes it easy for developers to add new methods or override default functionality,
15
+ leading to increased scalability and flexibility for your web applications.
16
+
17
+ #
18
+
19
+ ## Installation
20
+
21
+ To install TurboServer, simply run the following command:
22
+
23
+ ```
24
+ npm install turbo-express-js
25
+ ```
26
+
27
+ ## Getting Started
28
+
29
+ Here's a simple example of how to create a basic server using TurboServer:
30
+
31
+ ``` javascript
32
+
33
+ const TurboServer = require('turboserver');
34
+
35
+ const app = new TurboServer(1);
36
+
37
+ app.get('/', (req, res) => {
38
+ res.send('Hello, World!');
39
+ });
40
+
41
+ app.listen(3000, () => {
42
+ console.log('Server started on port 3000');
43
+ });
44
+ ```
45
+
46
+ # Clustering
47
+
48
+ TurboServer is built to support clustering out of the box. By passing a number to the TurboServer constructor, you can specify how many worker processes to spawn for your application.
49
+
50
+ In the example above, const app = new TurboServer(2) tells TurboServer to start two worker processes for the server. This allows the server to handle multiple requests simultaneously, improving the performance and scalability of your application.
51
+
52
+ To take full advantage of the clustering feature, it's important to make sure your application is stateless and doesn't rely on local variables or in-memory storage. With proper configuration, clustering can help your application handle a large number of requests with ease.
53
+
54
+ # Middlewares
55
+ TurboServer includes a number of built-in middlewares that you can use to add functionality to your application. Here are some of out of the box middlewares:
56
+
57
+ 1. Cors middleware
58
+ 2. Static middleware
59
+ 3. Upload middleware
60
+ 4. ValidaionMiddleware
61
+ 5. RunMethod middleware
62
+ 6. Authentication middleware
63
+ 7. BuildForm middleware // comming soon
64
+
65
+ Example:
66
+
67
+ > turbo-express-js/samples/middlewares.test.js
68
+
69
+ ``` javascript
70
+ const TurboExpress = require("turbo-express-js");
71
+ const RequestInterface = require("turbo-express-js/types/RequestInterface");
72
+ const ResponseInterface = require("turbo-express-js/types/ResponseInterface");
73
+
74
+ const app = new TurboExpress(1);
75
+
76
+ app.use("/*", TurboExpress.Cors({ origins: ["*"] })); // CORS middleware
77
+ app.get("/public/*", TurboExpress.Static({ folder: "/public" })); // Serve static files
78
+ app.post("/replace-attachments", TurboExpress.Upload({ memory: true, folder: "/storage" }), attachment_replace); // Handle attachment replacement
79
+ app.get("/run-method", TurboExpress.RunMethod({
80
+ exe: [{ isAsync: true, belong: "res", methodname: "test_runmethod", inject: "injected data" }]
81
+ })); // Execute methods of req or res without passing a controller function
82
+
83
+ // app.get("/something", TurboExpress.Validation()) // Look at example for request validation
84
+ // app.get("/something", TurboExpress.Authentication({ authentication_service: authenticationService })) // Look at example for authentication
85
+ // app.get("/user/new", TurboExpress.BuildForm()) // Work in progress
86
+
87
+ app.get("/:username", (req, res) => res.send("ok with cors: " + req.params().get("username")));
88
+
89
+ app.options("/*", (req, res) => res.send("ok")); // CORS :: in most cases u need to include this line because browser will send options request before the main request.
90
+
91
+ app.listen(5000);
92
+
93
+ /**
94
+ * @param {RequestInterface} req
95
+ * @param {ResponseInterface} res
96
+ */
97
+ async function attachment_replace(req, res) {
98
+ // req._files[0].is_saved // if not error this will be true
99
+ // req._files[0].save() // this method is used to save the file, file can be saved without middleware.
100
+ // req._files[0].unlink() // delete the file is it is saved, in case for some reason, file that was saved should be rolled back.
101
+
102
+ res.status(200).json({
103
+ body: await req.body(), // attachment properties will be replaced by url using Upload middleware.
104
+ files: req.files()
105
+ });
106
+ }
107
+ ```
108
+
109
+
110
+ # Basic Execution
111
+ Executing code in master and worker cluster processes.
112
+ > turbo-express-js/samples/exesomething.test.js
113
+
114
+ ``` javascript
115
+ const TurboExpress = require("turbo-express-js");
116
+ const app = new TurboExpress(2);
117
+
118
+ TurboExpress.exeMaster(async () => console.log("This callback is executed in the master cluster process."););
119
+ TurboExpress.exeWorker(async () => console.log("This callback is executed on each worker cluster process."););
120
+
121
+ app.listen(5000);
122
+ ```
123
+
124
+ ## Request Validation and Handling
125
+ Validate and handle HTTP requests with Turbo Express. (Out of the box feature)
126
+ > turbo-express-js/samples/validation.test.js
127
+
128
+ ``` javascript
129
+ const TurboExpress = require("turbo-express-js");
130
+ const RequestInterface = require("turbo-express-js/types/RequestInterface");
131
+ const ResponseInterface = require("turbo-express-js/types/ResponseInterface");
132
+
133
+ const app = new TurboExpress(1);
134
+
135
+ /**
136
+ * @param {RequestInterface} req
137
+ * @param {ResponseInterface} res
138
+ */
139
+ async function create_user(req, res) {
140
+ res.status(200).json({
141
+ body: await req.body(), // Contains all properties sent to the server
142
+ valid_data: req.validDataObj(), // Contains only properties included in the validation schema
143
+ files: req.files() // Returns a list of files
144
+ // Files are also mentioned in the body and valid_data as: <key or property>: <attachment::random id>
145
+ });
146
+ }
147
+
148
+ app.post("/create_user", TurboExpress.Validation({
149
+ validations: [
150
+ new TurboExpress.ValidationTypes.ValidationSchema(
151
+ "email",
152
+ [
153
+ { name: TurboExpress.ValidationTypes.ValidationName.ISREQUIRED },
154
+ { name: TurboExpress.ValidationTypes.ValidationName.MINLENGTH, value: 5 },
155
+ { name: TurboExpress.ValidationTypes.ValidationName.MAXLENGTH, value: 28 },
156
+ { name: TurboExpress.ValidationTypes.ValidationName.CONTAIN, value: "kristina" },
157
+ { name: TurboExpress.ValidationTypes.ValidationName.NOT_CONTAIN, value: " " },
158
+ { name: TurboExpress.ValidationTypes.ValidationName.ENDSWIDTH, value: ".com" },
159
+ { name: TurboExpress.ValidationTypes.ValidationName.VALID_EMAIL },
160
+ ],
161
+ true, // Is required?
162
+ null, // Default value
163
+ "body" // Namespace: <body, query, params, formdata>
164
+ ),
165
+ new TurboExpress.ValidationTypes.ValidationSchema(
166
+ "avatar",
167
+ [
168
+ { name: TurboExpress.ValidationTypes.ValidationName.ATTACHMENT_REQUIRED },
169
+ { name: TurboExpress.ValidationTypes.ValidationName.ATTACHMENT_EXTENSION, value: "jpeg" },
170
+ ],
171
+ true, // Is required?
172
+ null, // Default value
173
+ "body" // Namespace: <body, query, params, formdata>
174
+ )
175
+ ]
176
+ }), create_user);
177
+
178
+ app.listen(5000);
179
+ ```
180
+ This section demonstrates how to validate and handle HTTP requests using Turbo Express. The example includes a create_user function that serves as the request handler. If the request passes the validation, the handler function processes the request and sends a response. However, if the request does not pass the validation, Turbo Express automatically returns a 400 response with the validation errors. Additionally, Turbo Express provides a ValidationError class/interface that you can override for handling custom error messages and supporting multiple languages. For more advanced usage and customization options, refer to the official documentation of Turbo Express at the project's website.
181
+
182
+ ## Authentication and Authorization
183
+ Implement user authentication and authorization using Turbo Express. (Out of the box feature)
184
+ > turbo-express-js/samples/authentication.test.js
185
+
186
+ ``` javascript
187
+ const TurboExpress = require("turbo-express-js");
188
+ const RequestInterface = require("turbo-express-js/types/RequestInterface");
189
+ const ResponseInterface = require("turbo-express-js/types/ResponseInterface");
190
+
191
+
192
+ const app = new TurboExpress(1);
193
+
194
+ // class MyAuthenticationService extends TurboExpress.TurboExpressDefault.JWTBcryptMongoDBAuthService; Work Completed but documetation will come soon. Class that already implements all the required methods using MongoDB database, jwt and bcryptjs.
195
+
196
+ class MyAuthenticationService extends TurboExpress.ExpressServices.AuthenticationService {
197
+
198
+ // Override default values if needed
199
+ // secret
200
+ // secret_tmp
201
+ // user_key_value_properties
202
+
203
+ async find_user(login_value)
204
+ {
205
+ // Find the actual user in the database or from an external service using the login_value (e.g., email, phone number, username)
206
+ if (login_value === "katia") return { user_id: "1", email: "katia@gmail.com", username: "@katia" };
207
+ return null; // User not found or unauthorized (401)
208
+ }
209
+
210
+ async compare_password(user, password)
211
+ {
212
+ return true; // Compare user.password with the incoming password (Note: Do not use this implementation in production)
213
+ }
214
+
215
+ get_token(req)
216
+ {
217
+ return req.headers()["authentication"]; // Get the token from headers or cookies and manipulate if needed
218
+ }
219
+
220
+ async do_something_with_pin(pin)
221
+ {
222
+ console.log("\n" + pin + "\n"); // Do something with the generated pin (e.g., send an email)
223
+ }
224
+
225
+ // Optional methods (not required to be implemented)
226
+ // signToken() {} // You need to install the jsonwebtoken library to use this method
227
+ // verifyToken() {} // You need to install the jsonwebtoken library to use this method
228
+ }
229
+
230
+ const authService = new MyAuthenticationService();
231
+
232
+ // Simple login: <login_value, password> => returns a token
233
+ app.post("/login", async (req, res) => await authService.simpleLogin(req, res));
234
+
235
+ // Login workflow case #1: <login_value, password> => returns a temporary token
236
+ // Login workflow case #2: <pin, tmp token> => returns a token
237
+ app.post("/double-login", async (req, res) => await authService.doubleLoginWorkflow(req, res));
238
+
239
+ // Authenticated route
240
+ app.get(
241
+ "/authenticated",
242
+ async (req, res, next) => await authService.authenticated(req, res, next),
243
+ (req, res) => res.status(200).json(req.getStateObj())
244
+ );
245
+
246
+ app.listen(5000);
247
+ ```
248
+ This section demonstrates how to implement user authentication and authorization using Turbo Express. The example includes a custom MyAuthenticationService class that extends TurboExpress.ExpressServices.AuthenticationService. It provides methods for finding the user, comparing passwords, obtaining the token, and performing additional actions with the generated PIN. The class can be further extended and customized based on your authentication requirements. The example also shows how to use the authentication service by defining routes for simple login, double login workflow, and an authenticated route. Turbo Express handles the authentication process and provides convenient methods for validating user credentials and protecting routes. For more information and advanced usage scenarios, refer to the official documentation of Turbo Express at the project's website.
249
+
250
+ ## Custom Middleware
251
+
252
+ In addition to the built-in middlewares, TurboServer allows you to create your own custom middlewares for your application. Custom middleware functions can be used to add functionality to your application that is specific to your needs.
253
+
254
+ To create a custom middleware function, simply define a function that takes three parameters: the request object, the response object, and the next function. The next function is a callback that is used to pass control to the next middleware function in the chain.
255
+
256
+ Here's an example of a custom middleware function that logs the request method and URL to the console:
257
+
258
+ ``` javascript
259
+ function logger(req, res, next) {
260
+ console.log(`${req.method()} ${req.url()}`);
261
+ next();
262
+ }
263
+
264
+ app.use("/*", logger);
265
+ ```
266
+
267
+ In the above example, we define a logger function that logs the request method and URL to the console, and then calls the next function to pass control to the next middleware function in the chain. We then use the app.use method to add the logger function as a middleware function for all routes in our application.
268
+
269
+ You can define as many custom middleware functions as you need, and they will be executed in the order in which they are added to the middleware stack.
270
+
271
+ ## Custom Middleware after controller
272
+
273
+ In TurboServer, you can define middleware that will run after the controller method has completed. This can be useful for tasks such as logging, error handling, or any other post-processing that needs to be done after the response has been sent.
274
+
275
+ To define an end middleware in TurboServer, you can use the useEndMiddleware method. This method takes a path pattern and one or more middleware functions as arguments. The middleware functions will be executed in the order they are passed to the method.
276
+
277
+ Here is an example of how to define an end middleware in TurboServer:
278
+
279
+ ``` javascript
280
+ app.useEndMiddleware("/api/*", (req, res, next) => {
281
+ console.log("End middleware #1");
282
+ next();
283
+ }, (req, res, next) => {
284
+ console.log("End middleware #2");
285
+ next();
286
+ });
287
+ ```
288
+
289
+ # Use Turbo Express as a pro
290
+
291
+ ## Extending Request and Response Interfaces
292
+
293
+ This example demonstrates how to extend the Request and Response interfaces provided by TurboExpress to add custom methods and functionality.
294
+ Use Turbo Express as a pro
295
+
296
+ > turbo-express-js/samples/authentication.test.js
297
+
298
+ ``` javascript
299
+ const TurboExpress = require("turbo-express-js");
300
+ const RequestInterface = require("turbo-express-js/types/RequestInterface");
301
+ const ResponseInterface = require("turbo-express-js/types/ResponseInterface");
302
+
303
+ const app = new TurboExpress(1);
304
+
305
+ class MyRequest extends RequestInterface
306
+ {
307
+ mymethod ()
308
+ {
309
+ return `Hello ${this.params().get("username")}, I am Kristina !!`;
310
+ }
311
+ }
312
+
313
+ class MyResponse extends ResponseInterface
314
+ {
315
+ my_response_method (req)
316
+ {
317
+ this.status(200).json({ message: req.mymethod() })
318
+ }
319
+ }
320
+
321
+ app.Request = MyRequest;
322
+ app.Response = MyResponse;
323
+
324
+
325
+ app.get("/:username", controller);
326
+
327
+ app.listen(5000);
328
+
329
+ /**
330
+ * @param {MyRequest} req
331
+ * @param {MyResponse} res
332
+ */
333
+ async function controller (req, res) {
334
+ res.my_response_method(req);
335
+ }
336
+ ```
337
+
338
+ ## Locales
339
+
340
+ Using multiple languages in TurboExpress JS
341
+
342
+ ``` javascript
343
+ app.setLocales("/locales");
344
+ // req.current_locale // getting current locale from query parameters <locale> | Enum<string | can be only one of the folders inside /locales>
345
+ // req.getText() // using texts in multiple languages
346
+ ```
347
+
348
+ ## Request Validation and Handling As a PRO
349
+
350
+ Use custom validation error messages (multiple locales for instance)
351
+ > turbo-express-js/samples/validation_override.test.js
352
+
353
+ ``` javascript
354
+ const TurboExpress = require("turbo-express-js/TurboServer"); // replace this line with := const TurboExpress = require("turbo-express-js")
355
+ const RequestInterface = require("turbo-express-js/types/RequestInterface");
356
+ const ResponseInterface = require("turbo-express-js/types/ResponseInterface");
357
+
358
+ const app = new TurboExpress(1);
359
+
360
+
361
+ class CustomValidationError extends TurboExpress.ValidationTypes.ValidationError
362
+ {
363
+ /** @override */
364
+ addContainError (value)
365
+ {
366
+ // ORIGINAL ~> this.errors.push(`Property ${this.property} should contain ${value}`);
367
+ this.errors.push(`Property ${this.property} should contain ${value} | My own validation error message. `);
368
+ }
369
+ /** @override */
370
+ build (req)
371
+ {
372
+ return {
373
+ namespace: this.namespace,
374
+ property: this.property,
375
+ value: this.value,
376
+ errors: this.errors,
377
+ custom_property: "My own costum property, generated by Kristina AI."
378
+ }
379
+ }
380
+ }
381
+ class CustomRequest extends RequestInterface { ValidationError = CustomValidationError; } // Add Custom ValidationError Class to the Request
382
+ app.Request = CustomRequest; // Register your Request Class to the application
383
+
384
+ /**
385
+ * @param {RequestInterface} req
386
+ * @param {ResponseInterface} res
387
+ */
388
+ async function create_user(req, res) {
389
+ res.status(200).json({
390
+ body: await req.body(), // Contains all properties sent to the server
391
+ valid_data: req.validDataObj(), // Contains only properties included in the validation schema
392
+ files: req.files() // Returns a list of files
393
+ // Files are also mentioned in the body and valid_data as: <key or property>: <attachment::random id>
394
+ });
395
+ }
396
+
397
+ app.post("/create_user", TurboExpress.Validation({
398
+ validations: [
399
+ new TurboExpress.ValidationTypes.ValidationSchema(
400
+ "email",
401
+ [
402
+ { name: TurboExpress.ValidationTypes.ValidationName.ISREQUIRED },
403
+ { name: TurboExpress.ValidationTypes.ValidationName.MINLENGTH, value: 5 },
404
+ { name: TurboExpress.ValidationTypes.ValidationName.MAXLENGTH, value: 28 },
405
+ { name: TurboExpress.ValidationTypes.ValidationName.CONTAIN, value: "kristina" },
406
+ { name: TurboExpress.ValidationTypes.ValidationName.NOT_CONTAIN, value: " " },
407
+ { name: TurboExpress.ValidationTypes.ValidationName.ENDSWIDTH, value: ".com" },
408
+ { name: TurboExpress.ValidationTypes.ValidationName.VALID_EMAIL },
409
+ ],
410
+ true, // Is required?
411
+ null, // Default value
412
+ "body" // Namespace: <body, query, params, formdata>
413
+ ),
414
+ new TurboExpress.ValidationTypes.ValidationSchema(
415
+ "avatar",
416
+ [
417
+ { name: TurboExpress.ValidationTypes.ValidationName.ATTACHMENT_REQUIRED },
418
+ { name: TurboExpress.ValidationTypes.ValidationName.ATTACHMENT_EXTENSION, value: "jpeg" },
419
+ ],
420
+ true, // Is required?
421
+ null, // Default value
422
+ "body" // Namespace: <body, query, params, formdata>
423
+ )
424
+ ]
425
+ }), create_user);
426
+
427
+ app.listen(5000);
428
+ ```
429
+ This section demonstrates how to validate and handle HTTP requests using Turbo Express. The example includes a create_user function that serves as the request handler. If the request passes the validation, the handler function processes the request and sends a response. However, if the request does not pass the validation, Turbo Express automatically returns a 400 response with the validation errors. Additionally, Turbo Express provides a ValidationError class/interface that you can override for handling custom error messages and supporting multiple languages. For more advanced usage and customization options, refer to the official documentation of Turbo Express at the project's website.
430
+
431
+ ## Router
432
+
433
+ TurboServer offers a built-in Router to handle different HTTP methods and routes. The Router class is similar to the express.Router class, but it has some additional features. Here's a simple example of how to create a router and use it with TurboServer:
434
+
435
+ ``` javascript
436
+ const TurboServer = require('turboserver');
437
+
438
+ const app = new TurboServer(2);
439
+ const router = new TurboServer.Router();
440
+
441
+ router.get("/admin/:username", (req, res) => { res.send(req.params().get("username")) });
442
+
443
+ app.use('/api', router);
444
+
445
+ app.listen(3000, () => {
446
+ console.log('Server started on port 3000');
447
+ });
448
+
449
+ ```
450
+
451
+ ## About the Author
452
+
453
+ Our lead developer is a top-tier expert web and software engineer with mastery in over 20 programming languages, including Java, PHP, JavaScript, Golang, C, C++, and Python. With years of experience, they have built numerous open-source projects in these languages, including web, mobile, and desktop applications, as well as libraries and frameworks. Their expertise and passion for technology have been the driving force behind the creation of TurboServer, and they continue to work tirelessly to make it the fastest and most efficient web framework available.
454
+
455
+ #
456
+
457
+ ## Conclusion
458
+
459
+ TurboServer is a powerful and fast Node.js web framework that makes it easy to build high-performance web applications. With its built-in middlewares and simple API, it's a great choice for any project.
460
+
461
+ #
462
+
463
+ First deployment: 14/05/2023
464
+ Last deployment: 18/08/2023
465
+
466
+ STABLE VERSION: 1.0.8