tspace-spear 1.2.0 → 1.2.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.
Files changed (62) hide show
  1. package/README.md +777 -705
  2. package/{build → dist}/lib/core/decorators/context.js +86 -0
  3. package/dist/lib/core/decorators/context.js.map +1 -0
  4. package/dist/lib/core/decorators/controller.js +43 -0
  5. package/dist/lib/core/decorators/controller.js.map +1 -0
  6. package/dist/lib/core/decorators/headers.js +44 -0
  7. package/dist/lib/core/decorators/headers.js.map +1 -0
  8. package/dist/lib/core/decorators/methods.js +102 -0
  9. package/dist/lib/core/decorators/methods.js.map +1 -0
  10. package/dist/lib/core/decorators/middleware.js +61 -0
  11. package/dist/lib/core/decorators/middleware.js.map +1 -0
  12. package/dist/lib/core/decorators/statusCode.js +40 -0
  13. package/dist/lib/core/decorators/statusCode.js.map +1 -0
  14. package/dist/lib/core/decorators/swagger.js +52 -0
  15. package/dist/lib/core/decorators/swagger.js.map +1 -0
  16. package/{build → dist}/lib/core/server/index.js +272 -205
  17. package/dist/lib/core/server/index.js.map +1 -0
  18. package/{build → dist}/lib/core/server/parser-factory.js +29 -7
  19. package/dist/lib/core/server/parser-factory.js.map +1 -0
  20. package/dist/lib/core/server/radix-router.js +65 -0
  21. package/dist/lib/core/server/radix-router.js.map +1 -0
  22. package/{build → dist}/lib/core/server/router.js +34 -0
  23. package/dist/lib/core/server/router.js.map +1 -0
  24. package/{build → dist}/lib/index.js +0 -1
  25. package/{build → dist}/lib/index.js.map +1 -1
  26. package/{build → dist}/tests/benchmark.test.js +38 -8
  27. package/{build → dist}/tests/benchmark.test.js.map +1 -1
  28. package/package.json +15 -10
  29. package/build/lib/core/decorators/context.d.ts +0 -5
  30. package/build/lib/core/decorators/context.js.map +0 -1
  31. package/build/lib/core/decorators/controller.d.ts +0 -1
  32. package/build/lib/core/decorators/controller.js +0 -10
  33. package/build/lib/core/decorators/controller.js.map +0 -1
  34. package/build/lib/core/decorators/headers.d.ts +0 -3
  35. package/build/lib/core/decorators/headers.js +0 -15
  36. package/build/lib/core/decorators/headers.js.map +0 -1
  37. package/build/lib/core/decorators/index.d.ts +0 -9
  38. package/build/lib/core/decorators/methods.d.ts +0 -5
  39. package/build/lib/core/decorators/methods.js +0 -25
  40. package/build/lib/core/decorators/methods.js.map +0 -1
  41. package/build/lib/core/decorators/middleware.d.ts +0 -2
  42. package/build/lib/core/decorators/middleware.js +0 -24
  43. package/build/lib/core/decorators/middleware.js.map +0 -1
  44. package/build/lib/core/decorators/statusCode.d.ts +0 -1
  45. package/build/lib/core/decorators/statusCode.js +0 -16
  46. package/build/lib/core/decorators/statusCode.js.map +0 -1
  47. package/build/lib/core/decorators/swagger.d.ts +0 -2
  48. package/build/lib/core/decorators/swagger.js +0 -18
  49. package/build/lib/core/decorators/swagger.js.map +0 -1
  50. package/build/lib/core/server/index.d.ts +0 -312
  51. package/build/lib/core/server/index.js.map +0 -1
  52. package/build/lib/core/server/parser-factory.d.ts +0 -24
  53. package/build/lib/core/server/parser-factory.js.map +0 -1
  54. package/build/lib/core/server/router.d.ts +0 -79
  55. package/build/lib/core/server/router.js.map +0 -1
  56. package/build/lib/core/types/index.d.ts +0 -168
  57. package/build/lib/index.d.ts +0 -11
  58. package/build/tests/benchmark.test.d.ts +0 -1
  59. /package/{build → dist}/lib/core/decorators/index.js +0 -0
  60. /package/{build → dist}/lib/core/decorators/index.js.map +0 -0
  61. /package/{build → dist}/lib/core/types/index.js +0 -0
  62. /package/{build → dist}/lib/core/types/index.js.map +0 -0
package/README.md CHANGED
@@ -1,706 +1,778 @@
1
- # tspace-spear
2
-
3
- [![NPM version](https://img.shields.io/npm/v/tspace-spear.svg)](https://www.npmjs.com)
4
- [![NPM downloads](https://img.shields.io/npm/dm/tspace-spear.svg)](https://www.npmjs.com)
5
-
6
- tspace-spear is a lightweight API framework for Node.js that is fast and highly focused on providing the best developer experience.
7
- It utilizes the native HTTP server.
8
-
9
- ## Install
10
-
11
- Install with [npm](https://www.npmjs.com/):
12
-
13
- ```sh
14
- npm install tspace-spear --save
15
-
16
- ```
17
- ## Basic Usage
18
- - [Start Server](#start-server)
19
- - [Cluster](#cluster)
20
- - [Global Prefix](#global-prefix)
21
- - [Logger](#logger)
22
- - [Format Response](#format-response)
23
- - [Notfound](#notfound)
24
- - [Response](#response)
25
- - [Catch](#catch)
26
- - [Cors](#cors)
27
- - [Body](#body)
28
- - [File Upload](#file-upload)
29
- - [Cookie](#cookie)
30
- - [Middleware](#middleware)
31
- - [Controller](#controller)
32
- - [Router](#router)
33
- - [Swagger](#swagger)
34
- - [Example CRUD](#example-crud)
35
-
36
- ## Start Server
37
- ```js
38
- import { Spear } from "tspace-spear";
39
-
40
- new Spear()
41
- .get('/' , () => 'Hello world!')
42
- .get('/json' , () => {
43
- return {
44
- message : 'Hello world!'
45
- }
46
- })
47
- .listen(3000 , () => console.log(`Server is now listening http://localhost:3000`))
48
-
49
- ```
50
-
51
- ## Cluster
52
- ```js
53
- import { Spear } from "tspace-spear";
54
- new Spear({
55
- cluster : 3
56
- })
57
- .get('/' , () => 'Hello world!')
58
- .get('/json' , () => {
59
- return {
60
- message : 'Hello world!'
61
- }
62
- })
63
- .listen(3000 , () => console.log(`Server is now listening http://localhost:3000`))
64
-
65
- ```
66
-
67
- ## Global Prefix
68
- ```js
69
- const app = new Spear({
70
- globalPrefix : '/api' // prefix all routes
71
- })
72
- .get('/' , () => 'Hello world!')
73
- .listen(3000 , () => console.log(`Server is now listening http://localhost:3000`))
74
-
75
- // http://localhost:3000/api => 'Hello world!'
76
- ```
77
-
78
- ## Logger
79
- ```js
80
- const app = new Spear({
81
- logger : true
82
- })
83
- // or use this for logging
84
- .useLogger({
85
- methods : ['GET','POST'],
86
- exceptPath : /\/benchmark(\/|$)|\/favicon\.ico(\/|$)/ // or use Array ['/']
87
- })
88
- .get('/' , () => 'Hello world!')
89
- .listen(3000 , () => console.log(`Server is now listening http://localhost:3000`))
90
-
91
- ```
92
-
93
- ## Format Response
94
-
95
- ### Notfound
96
- ```js
97
- const app = new Spear()
98
- .get('/' , () => {
99
- return {
100
- message: 'Hello world'
101
- }
102
- })
103
- .notfound(({ res } : TContext) => {
104
- return res.notFound('Not found!')
105
- })
106
- .listen(3000 , () => console.log(`Server is now listening http://localhost:3000`))
107
- // http://localhost:3000/notfound => { success: false , message : 'Not found!' , statusCode: 404 }
108
-
109
- ```
110
-
111
- ### Response
112
- ```js
113
- const app = new Spear()
114
- .get('/' , () => {
115
- return {
116
- message: 'Hello world'
117
- }
118
- })
119
- .response((results, statusCode) => {
120
-
121
- if(typeof results === 'string') return results
122
-
123
- /// ...
124
- return {
125
- success : statusCode < 400,
126
- ...results,
127
- statusCode
128
- }
129
- })
130
- .listen(3000 , () => console.log(`Server is now listening http://localhost:3000`))
131
- // http://localhost:3000 => { success: true , message : 'Hello World' , statusCode: 200 }
132
-
133
- ```
134
-
135
- ### Catch
136
- ```js
137
- const app = new Spear()
138
- .get('/' , () => {
139
- throw new Error('Catching failed')
140
- })
141
- .catch((err : Error , { res } : TContext) => {
142
-
143
- return res
144
- .status(500)
145
- .json({
146
- success : false,
147
- message : err?.message,
148
- statusCode : 500
149
- });
150
- })
151
- .listen(3000 , () => console.log(`Server is now listening http://localhost:3000`))
152
- // http://localhost:3000 => { success: false , message : 'Catching failed' , statusCode: 500 }
153
-
154
- ```
155
-
156
- ## Cors
157
-
158
- ```js
159
- const app = new Spear()
160
- .cors({
161
- origins: [
162
- /^http:\/\/localhost:\d+$/
163
- ],
164
- credentials: true
165
- })
166
- //.cors() allow *
167
- .listen(port , () => console.log(`Server is now allow cors localhost:* `))
168
-
169
- ```
170
-
171
- ## Body
172
- ```js
173
-
174
- new Spear()
175
- // enable body payload
176
- .useBodyParser()
177
- .post('/' , ({ body }) => {
178
- return {
179
- yourBody : body
180
- }
181
- })
182
- .listen(3000 , () => console.log(`Server is now listening http://localhost:3000`))
183
-
184
- ```
185
-
186
- ## File Upload
187
-
188
- ```js
189
-
190
- import { Spear } from 'tspace-spear';
191
- import path from 'path'
192
-
193
- new Spear()
194
- // use this for enable file upload
195
- .useFileUpload({
196
- limit : 1000 * 1000, // limit for file upload 1_000_000 bytes by default Infinity
197
- tempFileDir : 'temp', // folder temporary directory by default tmp
198
- removeTempFile : {
199
- remove : true, // remove temporary files by default false
200
- ms : 1000 * 60 // remove file temporary after 60 seconds
201
- }
202
- })
203
- .post('/' , ({ files } : TContext) => {
204
-
205
- // you can move the file from temporary to other folder
206
- // for example please validate the your input file
207
- const file = files.file[0]
208
- const folder = 'uploads'
209
-
210
- await file.write(path.join(path.resolve(),`${folder}/${+new Date()}.${file.extension}`))
211
-
212
- // after writed the file you should remove the temporary file
213
- await file.remove()
214
-
215
- return {
216
- files
217
- }
218
- })
219
- .listen(3000 , () => console.log(`Server is now listening http://localhost:3000`))
220
-
221
- ```
222
-
223
- ## Cookie
224
- ```js
225
-
226
- new Spear()
227
- .useCookiesParser()
228
- .post('/' , ({ cookies }) => {
229
- return {
230
- yourCookies : cookies
231
- }
232
- })
233
- .listen(3000 , () => console.log(`Server is now listening http://localhost:3000`))
234
- ```
235
-
236
- ## Middleware
237
- ```js
238
- // file cat-middleware.ts
239
- export default (ctx : TContext, next: TNextFunction) =>{
240
- console.log('cat middleware globals');
241
- return next();
242
- }
243
-
244
- import Spear { Router, TContext, TNextFunction } from "tspace-spear";
245
- import CatMiddleware from './cat-middleware.ts'
246
-
247
- (async () => {
248
- const port = Number(process.env.PORT ?? 3000)
249
- const app = new Spear({
250
- middlewares: [ CatMiddleware ]
251
- // if you want to import middlewares with a directory can you follow the example
252
- // middlewares : {
253
- // folder : `${__dirname}/middlewares`,
254
- // name : /middleware\.(ts|js)$/i
255
- // }
256
- })
257
-
258
- // or add a middleware
259
- app.use((ctx : TContext , next : TNextFunction) => {
260
- console.log('global middlewares')
261
- return next()
262
- })
263
-
264
- app.get('/' ((ctx,next) => {
265
- console.log('middleware on the crrent route')
266
- return next()
267
- }), ({ res } : TContext) => {
268
- return res.json({
269
- message : 'hello world!'
270
- });
271
- })
272
-
273
- app.get('/' , ({ res } : TContext) => {
274
- return res.json({
275
- message : 'hello world!'
276
- });
277
- })
278
-
279
- app.listen(port , () => console.log(`Server is now listening http://localhost:3000`))
280
-
281
- // localhost:3000
282
-
283
- })()
284
- ```
285
-
286
- ## Controller
287
- ```js
288
- import {
289
- Controller ,
290
- Middleware ,
291
- Get ,
292
- Post,
293
- Patch,
294
- Put,
295
- Delete,
296
- WriteHeader,
297
- Query,
298
- Body,
299
- Params,
300
- Cookies,
301
- Files,
302
- StatusCode,
303
- TCookies,
304
- TParams,
305
- TRequest,
306
- TResponse ,
307
- TQuery,
308
- TFiles,
309
- TContext,
310
- TNextFunction
311
- } from 'tspace-spear';
312
-
313
- import CatMiddleware from './cat-middleware.ts'
314
-
315
- // file cat-controller.ts
316
- @Controller('/cats')
317
- class CatController {
318
- @Get('/')
319
- @Middleware(CatMiddleware)
320
- @Query('test','id')
321
- @Cookies('name')
322
- public async index({ query , cookies } : {
323
- query : TQuery<{ id : string }>
324
- cookies : TCookies<{ name : string}>
325
- }) {
326
-
327
- return {
328
- query,
329
- cookies
330
- }
331
- }
332
-
333
- @Get('/:id')
334
- @Middleware(CatMiddleware)
335
- @Params('id')
336
- public async show({ params } : TContext) {
337
- return {
338
- params
339
- }
340
- }
341
-
342
- @Post('/')
343
- @Middleware(CatMiddleware)
344
- public async store({ body } : TContext) {
345
- return {
346
- body
347
- }
348
- }
349
-
350
- @Put('/:id')
351
- @Middleware(CatMiddleware)
352
- public async update({ files } : TContext) {
353
- return {
354
- files
355
- }
356
- }
357
-
358
- @Post('/upload')
359
- @Middleware(CatMiddleware)
360
- public async upload({ files } : TContext) {
361
- return {
362
- files
363
- }
364
- }
365
-
366
- @Delete('/:id')
367
- @Middleware(CatMiddleware)
368
- public async destroy({ params } : TContext) {
369
- return {
370
- params
371
- }
372
- }
373
- }
374
-
375
- import { Spear } , { Router, TContext, TNextFunction } from "tspace-spear";
376
-
377
- import CatController from './cat-controller.ts'
378
-
379
- (async () => {
380
-
381
- const app = new Spear({
382
- controllers: [ CatController ]
383
- // if you want to import controllers with a directory can you follow the example
384
- // controllers : {
385
- // folder : `${__dirname}/controllers`,
386
- // name : /controller\.(ts|js)$/i
387
- // }
388
- })
389
-
390
- app.useBodyParser()
391
- app.useCookiesParser()
392
- app.useFileUpload()
393
-
394
- app.get('/' , ( { res } : TContext) => {
395
- return res.json({
396
- message : 'hello world!'
397
- });
398
- })
399
-
400
- app.listen(3000 , () => console.log(`Server is now listening http://localhost:3000`))
401
-
402
- // localhost:3000/cats
403
- // localhost:3000/cats/41
404
-
405
- })()
406
- ```
407
-
408
- ## Router
409
-
410
- ```js
411
- import { Spear } , { Router, TContext, TNextFunction } from "tspace-spear";
412
-
413
- const app = new Spear()
414
-
415
- const router = new Router()
416
-
417
- router.groups('/my',(r) => {
418
-
419
- r.get('/cats' , ({ req , res }) => {
420
-
421
- return res.json({
422
- message : 'Hello, World!'
423
- })
424
- })
425
-
426
- return r
427
- })
428
-
429
- router.get('/cats' , ({ req , res }) => {
430
- return res.json({
431
- message : 'Hello, World!'
432
- })
433
- })
434
-
435
- app.useRouter(router)
436
-
437
- app.get('/' , ({ res } : TContext) => {
438
- return res.json({
439
- message : 'hello world!'
440
- });
441
- })
442
-
443
- let port = 3000
444
-
445
- app.listen(port , () => console.log(`Server is now listening http://localhost:3000`))
446
-
447
- // localhost:3000/my/cats
448
- // localhost:3000/cats
449
-
450
- ```
451
-
452
- ## Swagger
453
- ```js
454
-
455
- // file cat-controller.ts
456
- import {
457
- TContext,
458
- Controller,
459
- Get ,
460
- Post,
461
- Put,
462
- Patch,
463
- Delete,
464
- Swagger
465
- } from 'tspace-spear';
466
-
467
- @Controller('/cats')
468
- class CatController {
469
- @Get('/')
470
- @Swagger({
471
- query : {
472
- id : {
473
- type : 'integer'
474
- },
475
- name : {
476
- type : 'string'
477
- }
478
- }
479
- })
480
- public async index({ query } : TContext) {
481
-
482
- return {
483
- query
484
- }
485
- }
486
-
487
- @Get('/:id')
488
- @Swagger({
489
- description : '- message',
490
- query : {
491
- id : {
492
- type : 'integer'
493
- }
494
- },
495
- responses : [
496
- { status : 200 , description : "OK" , example : { id : 'catz' }},
497
- { status : 400 , description : "Bad request" , example : { id : 'catz' }}
498
- ]
499
- })
500
- public async show({ params } : TContext) {
501
- return {
502
- params
503
- }
504
- }
505
-
506
- @Post('/')
507
- @Swagger({
508
- bearerToken : true,
509
- body : {
510
- description : 'The description !',
511
- required : true,
512
- properties : {
513
- id : {
514
- type : 'integer',
515
- example : 1
516
- },
517
- name : {
518
- type : 'string',
519
- example : "xxxxx"
520
- }
521
- }
522
- }
523
- })
524
- public async store({ body } : TContext) {
525
- return {
526
- body
527
- }
528
- }
529
-
530
- @Put('/:uuid')
531
- @Swagger({
532
- bearerToken : true,
533
- body : {
534
- description : 'The description !',
535
- required : true,
536
- properties : {
537
- id : {
538
- type : 'integer',
539
- example : 1
540
- },
541
- name : {
542
- type : 'string',
543
- example : "xxxxx"
544
- }
545
- }
546
- }
547
- })
548
- public async updated({ body } : TContext) {
549
- return {
550
- body
551
- }
552
- }
553
-
554
- @Patch('/:uuid')
555
- @Swagger({
556
- bearerToken : true,
557
- body : {
558
- description : 'The description !',
559
- required : true,
560
- properties : {
561
- id : {
562
- type : 'integer',
563
- example : 1
564
- },
565
- name : {
566
- type : 'string',
567
- example : "xxxxx"
568
- }
569
- }
570
- }
571
- })
572
- public async update({ body } : TContext) {
573
- return {
574
- body
575
- }
576
- }
577
-
578
- @Delete('/:uuid')
579
- @Swagger({
580
- bearerToken : true
581
- })
582
- public async delete({ params } : TContext) {
583
- return {
584
- params
585
- }
586
- }
587
-
588
- @Post('/upload')
589
- @Swagger({
590
- bearerToken : true,
591
- files : {
592
- required : true,
593
- properties : {
594
- file : {
595
- type : 'array',
596
- items: {
597
- type:"file",
598
- format:"binary"
599
- }
600
- },
601
- name : {
602
- type : 'string'
603
- }
604
- }
605
- }
606
- })
607
- public async upload({ body , files } : TContext) {
608
- return {
609
- body,
610
- files
611
- }
612
- }
613
- }
614
-
615
- (async () => {
616
-
617
- await new Spear({
618
- controllers: [ CatController ]
619
- })
620
- .get('/' , ({ res } : TContext) => {
621
- return res.json({
622
- message : 'hello world!'
623
- });
624
- })
625
- // .useSwagger() // by default path is "/api/docs"
626
- .useSwagger({
627
- path : "/docs",
628
- servers : [
629
- { url : "http://localhost:3000" , description : "development"},
630
- { url : "http://localhost:8000" , description : "production"}
631
- ],
632
- info : {
633
- "title" : "Welcome to the the documentation",
634
- "description" : "This is the documentation"
635
- }
636
- })
637
- .listen(3000 , () => console.log(`Server is now listening http://localhost:3000`))
638
-
639
- // localhost:3000/docs
640
- })()
641
-
642
- ```
643
-
644
- ## Example CRUD
645
- ```js
646
- import { Spear } from "tspace-spear";
647
-
648
- const spears = [
649
- {
650
- id : 1,
651
- damage : 100
652
- },
653
- {
654
- id : 2,
655
- damage : 75
656
- },
657
- {
658
- id : 3,
659
- damage : 50
660
- }
661
- ]
662
-
663
- new Spear()
664
- // enable body payload
665
- .useBodyParser()
666
- .get('/' , () => spears)
667
- .get('/:id' , ({ params }) => spears.find(spear => spear.id === Number(params.id ?? 0)))
668
- .post('/' , ({ body }) => {
669
- // please validation the your body
670
- const damage = Number(body.damage ?? (Math.random() * 100).toFixed(0))
671
-
672
- const id = spears.reduce((max, spear) => spear.id > max ? spear.id : max, 0) + 1
673
-
674
- spears.push({ id , damage })
675
-
676
- return spears.find(spear => spear.id === id)
677
- })
678
- .patch('/:id' , ({ params , body , res }) => {
679
-
680
- const damage = Number(body.damage ?? (Math.random() * 100).toFixed(0))
681
-
682
- const id = Number(params.id)
683
-
684
- const spear = spears.find(spear => spear.id === id)
685
-
686
- if (spear == null) return res.status(404).json({ message : 'Spear not found'})
687
-
688
- spear.damage = damage;
689
-
690
- return spears.find(spear => spear.id === id)
691
- })
692
- .delete('/:id', ({ params , res }) => {
693
-
694
- const id = Number(params.id)
695
-
696
- const spear = spears.find(spear => spear.id === id)
697
-
698
- if (spear == null) return res.status(404).json({ message : 'Spear not found'})
699
-
700
- spears.splice(spears.findIndex(spear => spear.id === Number(params.id ?? 0)), 1)
701
-
702
- return res.status(204).json()
703
- })
704
- .listen(3000 , () => console.log(`Server is now listening http://localhost:3000`))
705
-
1
+ # tspace-spear
2
+
3
+ [![NPM version](https://img.shields.io/npm/v/tspace-spear.svg)](https://www.npmjs.com)
4
+ [![NPM downloads](https://img.shields.io/npm/dm/tspace-spear.svg)](https://www.npmjs.com)
5
+
6
+ tspace-spear is a lightweight API framework for Node.js that is fast and highly focused on providing the best developer experience.
7
+ It utilizes the native HTTP server.
8
+
9
+ ## Install
10
+
11
+ Install with [npm](https://www.npmjs.com/):
12
+
13
+ ```sh
14
+ npm install tspace-spear --save
15
+
16
+ ```
17
+ ## Basic Usage
18
+ - [Start Server](#start-server)
19
+ - [Cluster](#cluster)
20
+ - [Global Prefix](#global-prefix)
21
+ - [Logger](#logger)
22
+ - [Format Response](#format-response)
23
+ - [Notfound](#notfound)
24
+ - [Response](#response)
25
+ - [Catch](#catch)
26
+ - [Cors](#cors)
27
+ - [Body](#body)
28
+ - [File Upload](#file-upload)
29
+ - [Cookie](#cookie)
30
+ - [Middleware](#middleware)
31
+ - [Controller](#controller)
32
+ - [Router](#router)
33
+ - [Swagger](#swagger)
34
+ - [WebSocket](#web-socket)
35
+ - [Example CRUD](#example-crud)
36
+
37
+ ## Start Server
38
+ ```js
39
+ import { Spear } from "tspace-spear";
40
+
41
+ new Spear()
42
+ .get('/' , () => 'Hello world!')
43
+ .get('/json' , () => {
44
+ return {
45
+ message : 'Hello world!'
46
+ }
47
+ })
48
+ .listen(3000 , () => console.log(`Server is now listening http://localhost:3000`))
49
+
50
+ ```
51
+
52
+ ## Cluster
53
+ ```js
54
+ import { Spear } from "tspace-spear";
55
+ new Spear({
56
+ cluster : 3
57
+ })
58
+ .get('/' , () => 'Hello world!')
59
+ .get('/json' , () => {
60
+ return {
61
+ message : 'Hello world!'
62
+ }
63
+ })
64
+ .listen(3000 , () => console.log(`Server is now listening http://localhost:3000`))
65
+
66
+ ```
67
+
68
+ ## Global Prefix
69
+ ```js
70
+ const app = new Spear({
71
+ globalPrefix : '/api' // prefix all routes
72
+ })
73
+ .get('/' , () => 'Hello world!')
74
+ .listen(3000 , () => console.log(`Server is now listening http://localhost:3000`))
75
+
76
+ // http://localhost:3000/api => 'Hello world!'
77
+ ```
78
+
79
+ ## Logger
80
+ ```js
81
+ const app = new Spear({
82
+ logger : true
83
+ })
84
+ // or use this for logging
85
+ .useLogger({
86
+ methods : ['GET','POST'],
87
+ exceptPath : /\/benchmark(\/|$)|\/favicon\.ico(\/|$)/ // or use Array ['/']
88
+ })
89
+ .get('/' , () => 'Hello world!')
90
+ .listen(3000 , () => console.log(`Server is now listening http://localhost:3000`))
91
+
92
+ ```
93
+
94
+ ## Format Response
95
+
96
+ ### Notfound
97
+ ```js
98
+ const app = new Spear()
99
+ .get('/' , () => {
100
+ return {
101
+ message: 'Hello world'
102
+ }
103
+ })
104
+ .notfound(({ res } : T.Context) => {
105
+ return res.notFound('Not found!')
106
+ })
107
+ .listen(3000 , () => console.log(`Server is now listening http://localhost:3000`))
108
+ // http://localhost:3000/notfound => { success: false , message : 'Not found!' , statusCode: 404 }
109
+
110
+ ```
111
+
112
+ ### Response
113
+ ```js
114
+ import { Spear } from "tspace-spear";
115
+
116
+ const app = new Spear()
117
+ .get('/' , () => {
118
+ return {
119
+ message: 'Hello world'
120
+ }
121
+ })
122
+ .response((results, statusCode) => {
123
+
124
+ if (typeof results === 'string') return results
125
+
126
+ if (Array.isArray(results)) {
127
+ return {
128
+ success: statusCode < 400,
129
+ data: results,
130
+ statusCode
131
+ }
132
+ }
133
+
134
+ if (typeof results === 'object' && results !== null) {
135
+ return {
136
+ success: statusCode < 400,
137
+ ...results,
138
+ statusCode
139
+ }
140
+ }
141
+
142
+ return {
143
+ success: statusCode < 400,
144
+ data: results,
145
+ statusCode
146
+ }
147
+ })
148
+ .listen(3000 , () => console.log(`Server is now listening http://localhost:3000`))
149
+ // http://localhost:3000 => { success: true , message : 'Hello World' , statusCode: 200 }
150
+
151
+ ```
152
+
153
+ ### Catch
154
+ ```js
155
+ import { Spear } from "tspace-spear";
156
+ import { z } from "zod";
157
+ const app = new Spear()
158
+ .get('/' , () => {
159
+ throw new Error('Catching failed')
160
+ })
161
+ .catch((err, { res } : T.Context) => {
162
+
163
+ if(err instanceof z.ZodError) {
164
+ return res
165
+ .status(422)
166
+ .json({
167
+ success : false,
168
+ message: "Validation failed",
169
+ issues : err?.issues,
170
+ statusCode : 422
171
+ });
172
+ }
173
+
174
+ return res
175
+ .status(500)
176
+ .json({
177
+ success : false,
178
+ message : err?.message,
179
+ statusCode : 500
180
+ });
181
+ })
182
+ .listen(3000 , () => console.log(`Server is now listening http://localhost:3000`))
183
+ // http://localhost:3000 => { success: false , message : 'Catching failed' , statusCode: 500 }
184
+
185
+ ```
186
+
187
+ ## Cors
188
+
189
+ ```js
190
+ const app = new Spear()
191
+ .cors({
192
+ origins: [
193
+ /^http:\/\/localhost:\d+$/
194
+ ],
195
+ credentials: true
196
+ })
197
+ //.cors() allow *
198
+ .listen(port , () => console.log(`Server is now allow cors localhost:* `))
199
+
200
+ ```
201
+
202
+ ## Body
203
+ ```js
204
+
205
+ new Spear()
206
+ // enable body payload
207
+ .useBodyParser()
208
+ .post('/' , ({ body }) => {
209
+ return {
210
+ yourBody : body
211
+ }
212
+ })
213
+ .listen(3000 , () => console.log(`Server is now listening http://localhost:3000`))
214
+
215
+ ```
216
+
217
+ ## File Upload
218
+
219
+ ```js
220
+
221
+ import { Spear, type T } from 'tspace-spear';
222
+ import path from 'path'
223
+
224
+ new Spear()
225
+ // use this for enable file upload
226
+ .useFileUpload({
227
+ limit : 1000 * 1000, // limit for file upload 1_000_000 bytes by default Infinity
228
+ tempFileDir : 'temp', // folder temporary directory by default tmp
229
+ removeTempFile : {
230
+ remove : true, // remove temporary files by default false
231
+ ms : 1000 * 60 // remove file temporary after 60 seconds
232
+ }
233
+ })
234
+ .post('/' , ({ files } : T.Context) => {
235
+
236
+ // you can move the file from temporary to other folder
237
+ // for example please validate the your input file
238
+ const file = files.file[0]
239
+ const folder = 'uploads'
240
+
241
+ await file.write(path.join(path.resolve(),`${folder}/${+new Date()}.${file.extension}`))
242
+
243
+ // after writed the file you should remove the temporary file
244
+ await file.remove()
245
+
246
+ return {
247
+ files
248
+ }
249
+ })
250
+ .listen(3000 , () => console.log(`Server is now listening http://localhost:3000`))
251
+
252
+ ```
253
+
254
+ ## Cookie
255
+ ```js
256
+
257
+ new Spear()
258
+ .useCookiesParser()
259
+ .post('/' , ({ cookies }) => {
260
+ return {
261
+ yourCookies : cookies
262
+ }
263
+ })
264
+ .listen(3000 , () => console.log(`Server is now listening http://localhost:3000`))
265
+ ```
266
+
267
+ ## Middleware
268
+ ```js
269
+ import { type T } from "tspace-spear"
270
+ // file cat-middleware.ts
271
+ export default (ctx : T.Context, next: T.NextFunction) =>{
272
+ console.log('cat middleware globals');
273
+ return next();
274
+ }
275
+
276
+ import Spear { Router, type T } from "tspace-spear";
277
+ import CatMiddleware from './cat-middleware.ts'
278
+
279
+ (async () => {
280
+ const port = Number(process.env.PORT ?? 3000)
281
+ const app = new Spear({
282
+ middlewares: [ CatMiddleware ]
283
+ // if you want to import middlewares with a directory can you follow the example
284
+ // middlewares : {
285
+ // folder : `${__dirname}/middlewares`,
286
+ // name : /middleware\.(ts|js)$/i
287
+ // }
288
+ })
289
+
290
+ // or add a middleware
291
+ app.use((ctx : T.Context , next : T.NextFunction) => {
292
+ console.log('global middlewares')
293
+ return next()
294
+ })
295
+
296
+ app.get('/' ((ctx,next) => {
297
+ console.log('middleware on the crrent route')
298
+ return next()
299
+ }), ({ res } : T.Context) => {
300
+ return res.json({
301
+ message : 'hello world!'
302
+ });
303
+ })
304
+
305
+ app.get('/' , ({ res } : T.Context) => {
306
+ return res.json({
307
+ message : 'hello world!'
308
+ });
309
+ })
310
+
311
+ app.listen(port , () => console.log(`Server is now listening http://localhost:3000`))
312
+
313
+ // localhost:3000
314
+
315
+ })()
316
+ ```
317
+
318
+ ## Controller
319
+ ```js
320
+ import {
321
+ Controller ,
322
+ Middleware ,
323
+ Get ,
324
+ Post,
325
+ Patch,
326
+ Put,
327
+ Delete,
328
+ WriteHeader,
329
+ Query,
330
+ Body,
331
+ Params,
332
+ Cookies,
333
+ Files,
334
+ StatusCode,
335
+ type T
336
+ } from 'tspace-spear';
337
+
338
+ import CatMiddleware from './cat-middleware.ts'
339
+
340
+ // file cat-controller.ts
341
+ @Controller('/cats')
342
+ class CatController {
343
+ @Get('/')
344
+ @Middleware(CatMiddleware)
345
+ @Query('test','id')
346
+ @Cookies('name')
347
+ public async index({ query , cookies } : {
348
+ query : T.Query<{ id : string }>
349
+ cookies : T.Cookies<{ name : string}>
350
+ }) {
351
+
352
+ return {
353
+ query,
354
+ cookies
355
+ }
356
+ }
357
+
358
+ @Get('/:id')
359
+ @Middleware(CatMiddleware)
360
+ @Params('id')
361
+ public async show({ params } : T.Context) {
362
+ return {
363
+ params
364
+ }
365
+ }
366
+
367
+ @Post('/')
368
+ @Middleware(CatMiddleware)
369
+ public async store({ body } : T.Context) {
370
+ return {
371
+ body
372
+ }
373
+ }
374
+
375
+ @Put('/:id')
376
+ @Middleware(CatMiddleware)
377
+ public async update({ files } : T.Context) {
378
+ return {
379
+ files
380
+ }
381
+ }
382
+
383
+ @Post('/upload')
384
+ @Middleware(CatMiddleware)
385
+ public async upload({ files } : T.Context) {
386
+ return {
387
+ files
388
+ }
389
+ }
390
+
391
+ @Delete('/:id')
392
+ @Middleware(CatMiddleware)
393
+ public async destroy({ params } : T.Context) {
394
+ return {
395
+ params
396
+ }
397
+ }
398
+ }
399
+
400
+ import { Spear } , { Router, type T } from "tspace-spear";
401
+
402
+ import CatController from './cat-controller.ts'
403
+
404
+ (async () => {
405
+
406
+ const app = new Spear({
407
+ controllers: [ CatController ]
408
+ // if you want to import controllers with a directory can you follow the example
409
+ // controllers : {
410
+ // folder : `${__dirname}/controllers`,
411
+ // name : /controller\.(ts|js)$/i
412
+ // }
413
+ })
414
+
415
+ app.useBodyParser()
416
+ app.useCookiesParser()
417
+ app.useFileUpload()
418
+
419
+ app.get('/' , ( { res } : T.Context) => {
420
+ return res.json({
421
+ message : 'hello world!'
422
+ });
423
+ })
424
+
425
+ app.listen(3000 , () => console.log(`Server is now listening http://localhost:3000`))
426
+
427
+ // localhost:3000/cats
428
+ // localhost:3000/cats/41
429
+
430
+ })()
431
+ ```
432
+
433
+ ## Router
434
+
435
+ ```js
436
+ import { Spear, Router, type T } from "tspace-spear";
437
+
438
+ const app = new Spear()
439
+
440
+ const router = new Router()
441
+
442
+ router.groups('/my',(r) => {
443
+
444
+ r.get('/cats' , ({ req , res }) => {
445
+
446
+ return res.json({
447
+ message : 'Hello, World!'
448
+ })
449
+ })
450
+
451
+ return r
452
+ })
453
+
454
+ router.get('/cats' , ({ req , res }) => {
455
+ return res.json({
456
+ message : 'Hello, World!'
457
+ })
458
+ })
459
+
460
+ app.useRouter(router)
461
+
462
+ app.get('/' , ({ res } : T.Context) => {
463
+ return res.json({
464
+ message : 'hello world!'
465
+ });
466
+ })
467
+
468
+ let port = 3000
469
+
470
+ app.listen(port , () => console.log(`Server is now listening http://localhost:3000`))
471
+
472
+ // localhost:3000/my/cats
473
+ // localhost:3000/cats
474
+
475
+ ```
476
+
477
+ ## Swagger
478
+ ```js
479
+
480
+ // file cat-controller.ts
481
+ import {
482
+ type T,
483
+ Controller,
484
+ Get ,
485
+ Post,
486
+ Put,
487
+ Patch,
488
+ Delete,
489
+ Swagger
490
+ } from 'tspace-spear';
491
+
492
+ @Controller('/cats')
493
+ class CatController {
494
+ @Get('/')
495
+ @Swagger({
496
+ query : {
497
+ id : {
498
+ type : 'integer'
499
+ },
500
+ name : {
501
+ type : 'string'
502
+ }
503
+ }
504
+ })
505
+ public async index({ query } : T.Context) {
506
+
507
+ return {
508
+ query
509
+ }
510
+ }
511
+
512
+ @Get('/:id')
513
+ @Swagger({
514
+ description : '- message',
515
+ query : {
516
+ id : {
517
+ type : 'integer'
518
+ }
519
+ },
520
+ responses : [
521
+ { status : 200 , description : "OK" , example : { id : 'catz' }},
522
+ { status : 400 , description : "Bad request" , example : { id : 'catz' }}
523
+ ]
524
+ })
525
+ public async show({ params } : T.Context) {
526
+ return {
527
+ params
528
+ }
529
+ }
530
+
531
+ @Post('/')
532
+ @Swagger({
533
+ bearerToken : true,
534
+ body : {
535
+ description : 'The description !',
536
+ required : true,
537
+ properties : {
538
+ id : {
539
+ type : 'integer',
540
+ example : 1
541
+ },
542
+ name : {
543
+ type : 'string',
544
+ example : "xxxxx"
545
+ }
546
+ }
547
+ }
548
+ })
549
+ public async store({ body } : T.Context) {
550
+ return {
551
+ body
552
+ }
553
+ }
554
+
555
+ @Put('/:uuid')
556
+ @Swagger({
557
+ bearerToken : true,
558
+ body : {
559
+ description : 'The description !',
560
+ required : true,
561
+ properties : {
562
+ id : {
563
+ type : 'integer',
564
+ example : 1
565
+ },
566
+ name : {
567
+ type : 'string',
568
+ example : "xxxxx"
569
+ }
570
+ }
571
+ }
572
+ })
573
+ public async updated({ body } : T.Context) {
574
+ return {
575
+ body
576
+ }
577
+ }
578
+
579
+ @Patch('/:uuid')
580
+ @Swagger({
581
+ bearerToken : true,
582
+ body : {
583
+ description : 'The description !',
584
+ required : true,
585
+ properties : {
586
+ id : {
587
+ type : 'integer',
588
+ example : 1
589
+ },
590
+ name : {
591
+ type : 'string',
592
+ example : "xxxxx"
593
+ }
594
+ }
595
+ }
596
+ })
597
+ public async update({ body } : T.Context) {
598
+ return {
599
+ body
600
+ }
601
+ }
602
+
603
+ @Delete('/:uuid')
604
+ @Swagger({
605
+ bearerToken : true
606
+ })
607
+ public async delete({ params } : T.Context) {
608
+ return {
609
+ params
610
+ }
611
+ }
612
+
613
+ @Post('/upload')
614
+ @Swagger({
615
+ bearerToken : true,
616
+ files : {
617
+ required : true,
618
+ properties : {
619
+ file : {
620
+ type : 'array',
621
+ items: {
622
+ type:"file",
623
+ format:"binary"
624
+ }
625
+ },
626
+ name : {
627
+ type : 'string'
628
+ }
629
+ }
630
+ }
631
+ })
632
+ public async upload({ body , files } : T.Context) {
633
+ return {
634
+ body,
635
+ files
636
+ }
637
+ }
638
+ }
639
+
640
+ (async () => {
641
+
642
+ await new Spear({
643
+ controllers: [ CatController ]
644
+ })
645
+ .get('/' , ({ res } : T.Context) => {
646
+ return res.json({
647
+ message : 'hello world!'
648
+ });
649
+ })
650
+ // .useSwagger() // by default path is "/api/docs"
651
+ .useSwagger({
652
+ path : "/docs",
653
+ servers : [
654
+ { url : "http://localhost:3000" , description : "development"},
655
+ { url : "http://localhost:8000" , description : "production"}
656
+ ],
657
+ info : {
658
+ "title" : "Welcome to the the documentation",
659
+ "description" : "This is the documentation"
660
+ }
661
+ })
662
+ .listen(3000 , () => console.log(`Server is now listening http://localhost:3000`))
663
+
664
+ // localhost:3000/docs
665
+ })()
666
+
667
+ ```
668
+
669
+ ## WebSocket
670
+ ```js
671
+ import { Spear } from "tspace-spear";
672
+
673
+ new Spear()
674
+ .get('/', () => 'Hello wor1ld!')
675
+ .post('/', ({ req , res , headers , query })=> {
676
+ return res.tooManyRequests()
677
+ })
678
+ .ws(() => {
679
+ return {
680
+ connection: (ws) => {
681
+ ws.send(JSON.stringify({ type: 'welcome', message: 'Welcome to the server!' }));
682
+ },
683
+ message: (ws, msg) => {
684
+ const data = JSON.parse(msg.toString());
685
+
686
+ switch (data.type) {
687
+ case 'chat':
688
+ console.log('Chat message:', data.text);
689
+ ws.send(JSON.stringify({ type: 'chat_ack', message: 'Chat received!' }));
690
+ break;
691
+
692
+ case 'ping':
693
+ console.log('Ping received');
694
+ ws.send(JSON.stringify({ type: 'pong' }));
695
+ break;
696
+
697
+ default:
698
+ ws.send(JSON.stringify({ type: 'error', message: 'Unknown message type' }));
699
+ }
700
+ },
701
+ close: (ws, code, reason) => {
702
+ console.log('Client disconnected');
703
+ },
704
+ error: (ws, error) => {
705
+ console.error('WebSocket error:', error);
706
+ }
707
+ }
708
+ })
709
+ .listen(3000 , ({ port , server }) => {
710
+ console.log(`server listening on : http://localhost:${port}`)
711
+ })
712
+
713
+
714
+ ```
715
+
716
+ ## Example CRUD
717
+ ```js
718
+ import { Spear } from "tspace-spear";
719
+
720
+ const spears = [
721
+ {
722
+ id : 1,
723
+ damage : 100
724
+ },
725
+ {
726
+ id : 2,
727
+ damage : 75
728
+ },
729
+ {
730
+ id : 3,
731
+ damage : 50
732
+ }
733
+ ]
734
+
735
+ new Spear()
736
+ // enable body payload
737
+ .useBodyParser()
738
+ .get('/' , () => spears)
739
+ .get('/:id' , ({ params }) => spears.find(spear => spear.id === Number(params.id ?? 0)))
740
+ .post('/' , ({ body }) => {
741
+ // please validation the your body
742
+ const damage = Number(body.damage ?? (Math.random() * 100).toFixed(0))
743
+
744
+ const id = spears.reduce((max, spear) => spear.id > max ? spear.id : max, 0) + 1
745
+
746
+ spears.push({ id , damage })
747
+
748
+ return spears.find(spear => spear.id === id)
749
+ })
750
+ .patch('/:id' , ({ params , body , res }) => {
751
+
752
+ const damage = Number(body.damage ?? (Math.random() * 100).toFixed(0))
753
+
754
+ const id = Number(params.id)
755
+
756
+ const spear = spears.find(spear => spear.id === id)
757
+
758
+ if (spear == null) return res.status(404).json({ message : 'Spear not found'})
759
+
760
+ spear.damage = damage;
761
+
762
+ return spears.find(spear => spear.id === id)
763
+ })
764
+ .delete('/:id', ({ params , res }) => {
765
+
766
+ const id = Number(params.id)
767
+
768
+ const spear = spears.find(spear => spear.id === id)
769
+
770
+ if (spear == null) return res.status(404).json({ message : 'Spear not found'})
771
+
772
+ spears.splice(spears.findIndex(spear => spear.id === Number(params.id ?? 0)), 1)
773
+
774
+ return res.status(204).json()
775
+ })
776
+ .listen(3000 , () => console.log(`Server is now listening http://localhost:3000`))
777
+
706
778
  ```