@anthonylzq/simba.js 9.0.0 → 9.1.0

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 (106) hide show
  1. package/README.md +65 -44
  2. package/lib/index.js +42 -5
  3. package/lib/src/functions/api/database.js +40 -218
  4. package/lib/src/functions/api/express.js +100 -604
  5. package/lib/src/functions/api/fastify.js +93 -645
  6. package/lib/src/functions/api/hono.js +157 -0
  7. package/lib/src/functions/api/index.js +37 -59
  8. package/lib/src/functions/api/schemas.js +20 -84
  9. package/lib/src/functions/api/services.js +28 -210
  10. package/lib/src/functions/api/utils.js +10 -432
  11. package/lib/src/functions/biome.js +3 -2
  12. package/lib/src/functions/changelog.js +5 -5
  13. package/lib/src/functions/docker.js +7 -39
  14. package/lib/src/functions/ghat.js +12 -94
  15. package/lib/src/functions/gitignore.js +3 -134
  16. package/lib/src/functions/index.js +1 -2
  17. package/lib/src/functions/license.js +10 -2
  18. package/lib/src/functions/packageJson.js +13 -37
  19. package/lib/src/functions/readme.js +6 -5
  20. package/lib/src/functions/tests.js +17 -320
  21. package/lib/src/functions/tsconfig.js +13 -114
  22. package/lib/src/index.js +45 -21
  23. package/lib/src/utils/entity.js +115 -0
  24. package/lib/src/utils/index.js +2 -0
  25. package/lib/src/utils/mkdirs.js +9 -0
  26. package/lib/src/utils/renderTemplate.js +22 -0
  27. package/lib/src/utils/titleCase.js +5 -10
  28. package/lib/src/utils/writeFile.js +3 -10
  29. package/lib/templates/api/database/connection.ts.ejs +40 -0
  30. package/lib/templates/api/database/db-index.ts.ejs +2 -0
  31. package/lib/templates/api/database/index.ts.ejs +1 -0
  32. package/lib/templates/api/database/queries-entity.ts.ejs +98 -0
  33. package/lib/templates/api/database/queries-index.ts.ejs +1 -0
  34. package/lib/templates/api/database/schema.prisma.ejs +25 -0
  35. package/lib/templates/api/express/network/index.ts.ejs +2 -0
  36. package/lib/templates/api/express/network/models/entity.ts.ejs +21 -0
  37. package/lib/templates/api/express/network/models/index.ts.ejs +1 -0
  38. package/lib/templates/api/express/network/resolvers/entity.ts.ejs +41 -0
  39. package/lib/templates/api/express/network/resolvers/index.ts.ejs +13 -0
  40. package/lib/templates/api/express/network/response.ts.ejs +17 -0
  41. package/lib/templates/api/express/network/router.ts.ejs +39 -0
  42. package/lib/templates/api/express/network/routes/docs.ts.ejs +43 -0
  43. package/lib/templates/api/express/network/routes/entity.ts.ejs +165 -0
  44. package/lib/templates/api/express/network/routes/home.ts.ejs +16 -0
  45. package/lib/templates/api/express/network/routes/index.ts.ejs +5 -0
  46. package/lib/templates/api/express/network/server.ts.ejs +139 -0
  47. package/lib/templates/api/express/network/utils/index.ts.ejs +45 -0
  48. package/lib/templates/api/express/types/graphQL/context.d.ts.ejs +3 -0
  49. package/lib/templates/api/express/types/index.d.ts.ejs +4 -0
  50. package/lib/templates/api/fastify/network/index.ts.ejs +2 -0
  51. package/lib/templates/api/fastify/network/models/entity.ts.ejs +21 -0
  52. package/lib/templates/api/fastify/network/models/index.ts.ejs +1 -0
  53. package/lib/templates/api/fastify/network/resolvers/entity.ts.ejs +41 -0
  54. package/lib/templates/api/fastify/network/resolvers/index.ts.ejs +13 -0
  55. package/lib/templates/api/fastify/network/response.ts.ejs +17 -0
  56. package/lib/templates/api/fastify/network/router.ts.ejs +36 -0
  57. package/lib/templates/api/fastify/network/routes/docs.ts.ejs +41 -0
  58. package/lib/templates/api/fastify/network/routes/entity.ts.ejs +116 -0
  59. package/lib/templates/api/fastify/network/routes/home.ts.ejs +15 -0
  60. package/lib/templates/api/fastify/network/routes/index.ts.ejs +5 -0
  61. package/lib/templates/api/fastify/network/server.ts.ejs +129 -0
  62. package/lib/templates/api/fastify/types/graphQL/context.d.ts.ejs +3 -0
  63. package/lib/templates/api/fastify/types/index.d.ts.ejs +4 -0
  64. package/lib/templates/api/hono/network/index.ts.ejs +2 -0
  65. package/lib/templates/api/hono/network/models/entity.ts.ejs +21 -0
  66. package/lib/templates/api/hono/network/models/index.ts.ejs +1 -0
  67. package/lib/templates/api/hono/network/resolvers/entity.ts.ejs +41 -0
  68. package/lib/templates/api/hono/network/resolvers/index.ts.ejs +13 -0
  69. package/lib/templates/api/hono/network/response.ts.ejs +18 -0
  70. package/lib/templates/api/hono/network/router.ts.ejs +45 -0
  71. package/lib/templates/api/hono/network/routes/docs.ts.ejs +39 -0
  72. package/lib/templates/api/hono/network/routes/entity.ts.ejs +104 -0
  73. package/lib/templates/api/hono/network/routes/home.ts.ejs +15 -0
  74. package/lib/templates/api/hono/network/routes/index.ts.ejs +5 -0
  75. package/lib/templates/api/hono/network/server.ts.ejs +160 -0
  76. package/lib/templates/api/hono/network/utils/index.ts.ejs +23 -0
  77. package/lib/templates/api/hono/types/graphQL/context.d.ts.ejs +3 -0
  78. package/lib/templates/api/hono/types/index.d.ts.ejs +4 -0
  79. package/lib/templates/api/schemas/entity.ts.ejs +43 -0
  80. package/lib/templates/api/schemas/id.ts.ejs +11 -0
  81. package/lib/templates/api/schemas/index.ts.ejs +2 -0
  82. package/lib/templates/api/services/BaseHttp.ts.ejs +73 -0
  83. package/lib/templates/api/services/entity.ts.ejs +75 -0
  84. package/lib/templates/api/services/index.ts.ejs +1 -0
  85. package/lib/templates/api/services/utils/index.ts.ejs +1 -0
  86. package/lib/templates/api/services/utils/messages/entity.ts.ejs +11 -0
  87. package/lib/templates/api/services/utils/messages/index.ts.ejs +6 -0
  88. package/lib/templates/api/utils/Logger.ts.ejs +41 -0
  89. package/lib/templates/api/utils/index.ts.ejs +1 -0
  90. package/lib/templates/config/.dockerignore.ejs +20 -0
  91. package/lib/templates/config/.env.ejs +3 -0
  92. package/lib/templates/config/.gitignore.ejs +129 -0
  93. package/lib/templates/config/CHANGELOG.md.ejs +1 -0
  94. package/lib/templates/config/Dockerfile.ejs +13 -0
  95. package/lib/templates/config/README.md.ejs +3 -0
  96. package/lib/templates/config/ghat/lint.yml.ejs +46 -0
  97. package/lib/templates/config/ghat/test.yml.ejs +29 -0
  98. package/lib/templates/config/index.ts.ejs +3 -0
  99. package/lib/templates/config/package.json.ejs +30 -0
  100. package/lib/templates/config/test/index.test.ts.ejs +260 -0
  101. package/lib/templates/config/tsconfig.base.json.ejs +43 -0
  102. package/lib/templates/config/tsconfig.json.ejs +16 -0
  103. package/lib/templates/config/vitest.config.ts.ejs +19 -0
  104. package/package.json +45 -17
  105. package/lib/src/functions/api/types.js +0 -108
  106. package/lib/src/functions/eslint.js +0 -125
@@ -0,0 +1,41 @@
1
+ import 'reflect-metadata'
2
+ import { Arg, Field, InputType, Mutation, Query, Resolver } from 'type-graphql'
3
+
4
+ import { <%- Entity %> } from 'network/models'
5
+ import { <%- Entity %>Service } from 'services'
6
+
7
+ @InputType()
8
+ class <%- Entity %>Input {
9
+ <% entityFields.forEach(function(f) { -%>
10
+ @Field()
11
+ <%- f.name %>!: string
12
+
13
+ <% }) -%>
14
+ }
15
+
16
+ @Resolver(<%- Entity %>)
17
+ class <%- Entity %>Resolver {
18
+ readonly #<%- entity %>Service = new <%- Entity %>Service()
19
+
20
+ @Query(() => <%- Entity %>)
21
+ async getById(@Arg('id') id: <%- dbIsSQL ? 'number' : 'string' %>) {
22
+ return this.#<%- entity %>Service.getById(id)
23
+ }
24
+
25
+ @Mutation(() => <%- Entity %>)
26
+ async store(@Arg('<%- entity %>') <%- entity %>: <%- Entity %>Input) {
27
+ return this.#<%- entity %>Service.store(<%- entity %>)
28
+ }
29
+
30
+ @Mutation(() => <%- Entity %>)
31
+ async update(@Arg('id') id: <%- dbIsSQL ? 'number' : 'string' %>, @Arg('<%- entity %>') <%- entity %>: <%- Entity %>Input) {
32
+ return this.#<%- entity %>Service.update(id, <%- entity %>)
33
+ }
34
+
35
+ @Mutation(() => String)
36
+ async deleteById(@Arg('id') id: <%- dbIsSQL ? 'number' : 'string' %>) {
37
+ return this.#<%- entity %>Service.deleteById(id)
38
+ }
39
+ }
40
+
41
+ export { <%- Entity %>Resolver }
@@ -0,0 +1,13 @@
1
+ import { buildSchema } from 'type-graphql'
2
+ import { <%- Entity %>Resolver } from './<%-Entity%>'
3
+
4
+ const buildSchemas = async () => {
5
+ const schema = await buildSchema({
6
+ resolvers: [<%- Entity %>Resolver],
7
+ validate: { forbidUnknownValues: false }
8
+ })
9
+
10
+ return schema
11
+ }
12
+
13
+ export { buildSchemas }
@@ -0,0 +1,17 @@
1
+ import type { Response } from 'express'
2
+
3
+ const response = ({
4
+ error,
5
+ message,
6
+ res,
7
+ status
8
+ }: {
9
+ error: boolean
10
+ message: unknown
11
+ res: Response
12
+ status: number
13
+ }) => {
14
+ res.status(status).send({ error, message })
15
+ }
16
+
17
+ export { response }
@@ -0,0 +1,39 @@
1
+ import type { Application, Response, Request, Router, NextFunction } from 'express'
2
+ import httpErrors from 'http-errors'
3
+
4
+ import { response } from './response'
5
+ <% if (graphQL) { -%>
6
+ import { Home, Docs } from './routes'
7
+ <% } else { -%>
8
+ import { Home, Docs, <%- Entity %> } from './routes'
9
+ <% } %>
10
+ <%- graphQL ? 'const routers: Router[] = [Docs]' : `const routers = [${Entity}, Docs]` %>
11
+ const applyRoutes = (app: Application): void => {
12
+ app.use('/', Home)
13
+ routers.forEach((router: Router) => {
14
+ app.use('/api', router)
15
+ })
16
+
17
+ // Handling 404 error
18
+ app.use((_req, _res, next) => {
19
+ next(new httpErrors.NotFound('This route does not exists'))
20
+ })
21
+ app.use(
22
+ (
23
+ error: httpErrors.HttpError,
24
+ _req: Request,
25
+ res: Response,
26
+ next: NextFunction
27
+ ) => {
28
+ response({
29
+ error: true,
30
+ message: error.message,
31
+ res,
32
+ status: error.status
33
+ })
34
+ next()
35
+ }
36
+ )
37
+ }
38
+
39
+ export { applyRoutes }
@@ -0,0 +1,43 @@
1
+ import { Router } from 'express'
2
+ import swaggerUi from 'swagger-ui-express'
3
+ import { OpenApiGeneratorV31 } from '@asteasolutions/zod-to-openapi'
4
+
5
+ import { registry } from 'network/utils'
6
+ import pkg from '../../../package.json'
7
+
8
+ const Docs = Router()
9
+
10
+ const generator = new OpenApiGeneratorV31(registry.definitions)
11
+ const docs = generator.generateDocument({
12
+ openapi: '3.1.0',
13
+ info: {
14
+ title: pkg.name,
15
+ description: pkg.description,
16
+ version: pkg.version,
17
+ contact: {
18
+ email: '<%- email %>'
19
+ },
20
+ license: {
21
+ name: 'MIT',
22
+ url: 'https://opensource.org/licenses/MIT'
23
+ }
24
+ },
25
+ servers: [
26
+ {
27
+ url: 'http://localhost:1996/api',
28
+ description: `${pkg.name} local API`
29
+ }
30
+ ],
31
+ tags: [
32
+ <% if (!graphQL) { -%>
33
+ {
34
+ name: '<%- entity %>',
35
+ description: '<%- Entity %> related endpoints'
36
+ }
37
+ <% } -%>
38
+ ]
39
+ })
40
+
41
+ Docs.use('/docs', swaggerUi.serve, swaggerUi.setup(docs))
42
+
43
+ export { Docs }
@@ -0,0 +1,165 @@
1
+ import { type NextFunction, type Request, type Response, Router } from 'express'
2
+ import z from 'zod'
3
+
4
+ import { response } from 'network/response'
5
+ import { jsonBody, jsonResponse, registry, validatorCompiler } from 'network/utils'
6
+ import { <%- entity %>Dto, idSchema, store<%- Entity %>Dto, type <%- Entity %>DTO } from 'schemas'
7
+ import { <%- Entity %>Service } from 'services'
8
+
9
+ const <%- Entity %> = Router()
10
+ const <%- entity %>Tag = '<%- entity %>'
11
+
12
+ // POST /<%- entities %>
13
+ <%- Entity %>.post(
14
+ '/<%-entities%>',
15
+ validatorCompiler(store<%- Entity %>Dto, 'body'),
16
+ async (
17
+ req: Request<
18
+ {
19
+ [key: string]: string
20
+ },
21
+ Record<string, unknown>,
22
+ { args: <%- Entity %>DTO }
23
+ >,
24
+ res: Response,
25
+ next: NextFunction
26
+ ): Promise<void> => {
27
+ try {
28
+ const {
29
+ body: {
30
+ args: { <%- entityFields.map(f => f.name).join(', ') %> }
31
+ }
32
+ } = req
33
+ const us = new <%- Entity %>Service()
34
+ const <%- entity %> = await us.store({ <%- entityFields.map(f => f.name).join(', ') %> })
35
+
36
+ response({ error: false, message: <%- entity %>, res, status: 201 })
37
+ } catch (error) {
38
+ next(error)
39
+ }
40
+ }
41
+ )
42
+
43
+ registry.registerPath({
44
+ method: 'post',
45
+ path: '/<%- entities %>',
46
+ tags: [<%- entity %>Tag],
47
+ request: {
48
+ body: jsonBody(store<%- Entity %>Dto)
49
+ },
50
+ responses: {
51
+ 201: jsonResponse(<%- entity %>Dto, '<%- Entity %> created successfully')
52
+ }
53
+ })
54
+
55
+ // GET /<%- entity %>/:id
56
+ <%- Entity %>.get(
57
+ '/<%-entity%>/:id',
58
+ validatorCompiler(idSchema, 'params'),
59
+ async (
60
+ req: Request<{ id: string }, Record<string, unknown>>,
61
+ res: Response,
62
+ next: NextFunction
63
+ ): Promise<void> => {
64
+ try {
65
+ const {
66
+ params: { id }
67
+ } = req
68
+ const us = new <%- Entity %>Service()
69
+ const <%- entity %> = await us.getById(<%- dbIsSQL ? 'parseInt(id)' : 'id' %>)
70
+
71
+ response({ error: false, message: <%- entity %>, res, status: 200 })
72
+ } catch (error) {
73
+ next(error)
74
+ }
75
+ }
76
+ )
77
+
78
+ registry.registerPath({
79
+ method: 'get',
80
+ path: '/<%- entity %>/{id}',
81
+ tags: [<%- entity %>Tag],
82
+ request: {
83
+ params: idSchema
84
+ },
85
+ responses: {
86
+ 200: jsonResponse(<%- entity %>Dto, '<%- Entity %> found')
87
+ }
88
+ })
89
+
90
+ // PATCH /<%- entity %>/:id
91
+ <%- Entity %>.patch(
92
+ '/<%-entity%>/:id',
93
+ validatorCompiler(idSchema, 'params'),
94
+ validatorCompiler(store<%- Entity %>Dto, 'body'),
95
+ async (
96
+ req: Request<{ id: string }, Record<string, unknown>, { args: <%- Entity %>DTO }>,
97
+ res: Response,
98
+ next: NextFunction
99
+ ): Promise<void> => {
100
+ try {
101
+ const {
102
+ body: {
103
+ args: { <%- entityFields.map(f => f.name).join(', ') %> }
104
+ },
105
+ params: { id }
106
+ } = req
107
+ const us = new <%- Entity %>Service()
108
+ const <%- entity %> = await us.update(<%- dbIsSQL ? 'parseInt(id)' : 'id' %>, { <%- entityFields.map(f => f.name).join(', ') %> })
109
+
110
+ response({ error: false, message: <%- entity %>, res, status: 200 })
111
+ } catch (error) {
112
+ next(error)
113
+ }
114
+ }
115
+ )
116
+
117
+ registry.registerPath({
118
+ method: 'patch',
119
+ path: '/<%- entity %>/{id}',
120
+ tags: [<%- entity %>Tag],
121
+ request: {
122
+ params: idSchema,
123
+ body: jsonBody(store<%- Entity %>Dto)
124
+ },
125
+ responses: {
126
+ 200: jsonResponse(<%- entity %>Dto, '<%- Entity %> updated successfully')
127
+ }
128
+ })
129
+
130
+ // DELETE /<%- entity %>/:id
131
+ <%- Entity %>.delete(
132
+ '/<%-entity%>/:id',
133
+ validatorCompiler(idSchema, 'params'),
134
+ async (
135
+ req: Request<{ id: string }>,
136
+ res: Response,
137
+ next: NextFunction
138
+ ): Promise<void> => {
139
+ try {
140
+ const {
141
+ params: { id }
142
+ } = req
143
+ const us = new <%- Entity %>Service()
144
+ const result = await us.deleteById(<%- dbIsSQL ? 'parseInt(id)' : 'id' %>)
145
+
146
+ response({ error: false, message: result, res, status: 200 })
147
+ } catch (error) {
148
+ next(error)
149
+ }
150
+ }
151
+ )
152
+
153
+ registry.registerPath({
154
+ method: 'delete',
155
+ path: '/<%- entity %>/{id}',
156
+ tags: [<%- entity %>Tag],
157
+ request: {
158
+ params: idSchema
159
+ },
160
+ responses: {
161
+ 200: jsonResponse(z.string(), '<%- Entity %> deleted successfully')
162
+ }
163
+ })
164
+
165
+ export { <%- Entity %> }
@@ -0,0 +1,16 @@
1
+ import { type Response, type Request, Router } from 'express'
2
+
3
+ import { response } from 'network/response'
4
+
5
+ const Home = Router()
6
+
7
+ Home.route('').get((_req: Request, res: Response) => {
8
+ response({
9
+ error: false,
10
+ message: 'Welcome to your Express Backend!',
11
+ res,
12
+ status: 200
13
+ })
14
+ })
15
+
16
+ export { Home }
@@ -0,0 +1,5 @@
1
+ export * from './home'
2
+ export * from './docs'
3
+ <% if (!graphQL) { -%>
4
+ export * from './<%-entity%>'
5
+ <% } -%>
@@ -0,0 +1,139 @@
1
+ import type { Server as HttpServer } from 'node:http'
2
+ import express from 'express'
3
+ import cors from 'cors'
4
+ import debug from 'debug'
5
+ <% if (graphQL) { -%>
6
+ import { ApolloServer } from '@apollo/server'
7
+ import { expressMiddleware } from '@as-integrations/express5'
8
+
9
+ import { dbConnection } from 'database'
10
+ import { applyRoutes } from './router'
11
+ import { buildSchemas } from './resolvers'
12
+ <% } else { -%>
13
+
14
+ import { dbConnection } from 'database'
15
+ import { applyRoutes } from './router'
16
+ <% } -%>
17
+ import type { Log } from 'utils'
18
+
19
+ const d = debug('App:Network:Server')
20
+ const PORT = (process.env.PORT as string) || 1996
21
+
22
+ class Server implements Log {
23
+ #app: express.Application
24
+ #server: HttpServer | undefined
25
+ #connection: Awaited<ReturnType<typeof dbConnection>>
26
+ <% if (graphQL) { -%>
27
+ #apolloServer: ApolloServer | undefined
28
+ <% } %>
29
+ constructor() {
30
+ this.#app = express()
31
+ this.#connection = dbConnection(d)
32
+ }
33
+
34
+ <% if (graphQL) { -%>
35
+ async #config() {
36
+ await this.#apolloConfig()
37
+ this.#app.use(cors())
38
+ <% } else { -%>
39
+ #config() {
40
+ this.#app.use(cors())
41
+ <% } -%>
42
+ this.#app.use(express.json())
43
+ this.#app.use(express.urlencoded({ extended: false }))
44
+ this.#app.use(
45
+ (
46
+ _req: express.Request,
47
+ res: express.Response,
48
+ next: express.NextFunction
49
+ ) => {
50
+ res.header('Access-Control-Allow-Methods', 'GET, POST, PATCH, DELETE')
51
+ res.header('Access-Control-Allow-Origin', '*')
52
+ res.header(
53
+ 'Access-Control-Allow-Headers',
54
+ 'Authorization, Content-Type'
55
+ )
56
+ res.header('x-powered-by', 'Simba.js')
57
+ next()
58
+ }
59
+ )
60
+ applyRoutes(this.#app)
61
+ }
62
+
63
+ <% if (graphQL) { -%>
64
+ async #apolloConfig() {
65
+ this.#apolloServer = new ApolloServer({
66
+ schema: await buildSchemas()
67
+ })
68
+ await this.#apolloServer.start()
69
+ this.#app.use(
70
+ '/graphql',
71
+ cors(),
72
+ express.json(),
73
+ expressMiddleware(this.#apolloServer)
74
+ )
75
+ }
76
+
77
+ async start() {
78
+ <% } else { -%>
79
+ async start(): Promise<void> {
80
+ <% } -%>
81
+ try {
82
+ <% if (graphQL) { -%>
83
+ await this.#config()
84
+ <% } else { -%>
85
+ this.#config()
86
+ <% } -%>
87
+ await this.#connection?.connect()
88
+ this.#server = this.#app.listen(PORT, () => {
89
+ d(`HTTP server listening on port ${PORT}.`)
90
+ })
91
+ } catch (e) {
92
+ this.log({
93
+ method: this.start.name,
94
+ value: 'error',
95
+ content: e
96
+ })
97
+ }
98
+ }
99
+
100
+ <% if (graphQL) { -%>
101
+ async stop() {
102
+ <% } else { -%>
103
+ async stop(): Promise<void> {
104
+ <% } -%>
105
+ try {
106
+ await this.#connection?.disconnect()
107
+ this.#server?.close()
108
+ <% if (graphQL) { -%>
109
+ await this.#apolloServer?.stop()
110
+ <% } -%>
111
+ } catch (e) {
112
+ this.log({
113
+ method: this.stop.name,
114
+ value: 'error',
115
+ content: e
116
+ })
117
+ }
118
+ }
119
+
120
+ log({
121
+ method,
122
+ value,
123
+ content
124
+ }: {
125
+ method: string
126
+ value: string
127
+ content: unknown
128
+ }) {
129
+ d(
130
+ `Server invoked -> ${
131
+ this.constructor.name
132
+ } ~ ${method} ~ value: ${value} ~ content: ${<%- graphQL ? 'content' : 'JSON.stringify(content)' %>}`
133
+ )
134
+ }
135
+ }
136
+
137
+ const server = new Server()
138
+
139
+ export { server as Server }
@@ -0,0 +1,45 @@
1
+ import type { NextFunction, Request, Response } from 'express'
2
+ import httpErrors from 'http-errors'
3
+ import { OpenAPIRegistry } from '@asteasolutions/zod-to-openapi'
4
+ import { type ZodType, z } from 'zod'
5
+
6
+ type Middleware = (req: Request, res: Response, next: NextFunction) => void
7
+
8
+ const registry = new OpenAPIRegistry()
9
+
10
+ const validatorCompiler = (
11
+ schema: ZodType,
12
+ value: 'body' | 'params'
13
+ ): Middleware => {
14
+ return (req: Request, _res: Response, next: NextFunction) => {
15
+ const result = schema.safeParse(req[value])
16
+
17
+ if (result.success) return next()
18
+
19
+ return next(
20
+ new httpErrors.UnprocessableEntity(JSON.stringify(result.error))
21
+ )
22
+ }
23
+ }
24
+
25
+ const jsonResponse = (schema: ZodType, description: string) => ({
26
+ description,
27
+ content: {
28
+ 'application/json': {
29
+ schema: z.object({
30
+ error: z.boolean(),
31
+ message: schema
32
+ })
33
+ }
34
+ }
35
+ })
36
+
37
+ const jsonBody = (schema: ZodType) => ({
38
+ content: {
39
+ 'application/json': {
40
+ schema
41
+ }
42
+ }
43
+ })
44
+
45
+ export { registry, validatorCompiler, jsonResponse, jsonBody }
@@ -0,0 +1,3 @@
1
+ type Context = {
2
+ log: (...args: unknown[]) => void
3
+ }
@@ -0,0 +1,4 @@
1
+ /* eslint-disable no-var */
2
+ declare global {}
3
+
4
+ export {}
@@ -0,0 +1,2 @@
1
+ export * from './routes'
2
+ export * from './server'
@@ -0,0 +1,21 @@
1
+ import 'reflect-metadata'
2
+ import { Field, <%- dbIsSQL ? 'Int' : 'ID' %>, ObjectType } from 'type-graphql'
3
+
4
+ @ObjectType()
5
+ class <%- Entity %> {
6
+ @Field(() => <%- dbIsSQL ? 'Int' : 'ID' %>)
7
+ id!: number
8
+
9
+ <% entityFields.forEach(function(f) { -%>
10
+ @Field()
11
+ <%- f.name %>!: string
12
+
13
+ <% }) -%>
14
+ @Field({ nullable: true })
15
+ createdAt?: string
16
+
17
+ @Field({ nullable: true })
18
+ updatedAt?: string
19
+ }
20
+
21
+ export { <%- Entity %> }
@@ -0,0 +1 @@
1
+ export * from './<%-Entity%>'
@@ -0,0 +1,41 @@
1
+ import 'reflect-metadata'
2
+ import { Arg, Field, InputType, Mutation, Query, Resolver } from 'type-graphql'
3
+
4
+ import { <%- Entity %> } from 'network/models'
5
+ import { <%- Entity %>Service } from 'services'
6
+
7
+ @InputType()
8
+ class <%- Entity %>Input {
9
+ <% entityFields.forEach(function(f) { -%>
10
+ @Field()
11
+ <%- f.name %>!: string
12
+
13
+ <% }) -%>
14
+ }
15
+
16
+ @Resolver(<%- Entity %>)
17
+ class <%- Entity %>Resolver {
18
+ readonly #<%- entity %>Service = new <%- Entity %>Service()
19
+
20
+ @Query(() => <%- Entity %>)
21
+ async getById(@Arg('id') id: <%- dbIsSQL ? 'number' : 'string' %>) {
22
+ return this.#<%- entity %>Service.getById(id)
23
+ }
24
+
25
+ @Mutation(() => <%- Entity %>)
26
+ async store(@Arg('<%- entity %>') <%- entity %>: <%- Entity %>Input) {
27
+ return this.#<%- entity %>Service.store(<%- entity %>)
28
+ }
29
+
30
+ @Mutation(() => <%- Entity %>)
31
+ async update(@Arg('id') id: <%- dbIsSQL ? 'number' : 'string' %>, @Arg('<%- entity %>') <%- entity %>: <%- Entity %>Input) {
32
+ return this.#<%- entity %>Service.update(id, <%- entity %>)
33
+ }
34
+
35
+ @Mutation(() => String)
36
+ async deleteById(@Arg('id') id: <%- dbIsSQL ? 'number' : 'string' %>) {
37
+ return this.#<%- entity %>Service.deleteById(id)
38
+ }
39
+ }
40
+
41
+ export { <%- Entity %>Resolver }
@@ -0,0 +1,13 @@
1
+ import { buildSchema } from 'type-graphql'
2
+ import { <%- Entity %>Resolver } from './<%-Entity%>'
3
+
4
+ const buildSchemas = async () => {
5
+ const schema = await buildSchema({
6
+ resolvers: [<%- Entity %>Resolver],
7
+ validate: { forbidUnknownValues: false }
8
+ })
9
+
10
+ return schema
11
+ }
12
+
13
+ export { buildSchemas }
@@ -0,0 +1,17 @@
1
+ import type { FastifyReply } from 'fastify'
2
+
3
+ const response = ({
4
+ error,
5
+ message,
6
+ reply,
7
+ status
8
+ }: {
9
+ error: boolean
10
+ message: unknown
11
+ reply: FastifyReply
12
+ status: number
13
+ }): void => {
14
+ reply.code(status).send({ error, message })
15
+ }
16
+
17
+ export { response }
@@ -0,0 +1,36 @@
1
+ import type { FastifyInstance } from 'fastify'
2
+ import { HttpError } from 'http-errors'
3
+
4
+ import { response } from './response'
5
+ <% if (graphQL) { -%>
6
+ import { Home, Docs } from './routes'
7
+ <% } else { -%>
8
+ import { Home, <%- Entity %>, Docs } from './routes'
9
+ <% } %>
10
+ <%- graphQL ? 'const routers = [Home]' : `const routers = [Home, ${Entity}]` %>
11
+ const applyRoutes = async (app: FastifyInstance) => {
12
+ routers.forEach(router => {
13
+ router(app)
14
+ })
15
+ await Docs(app)
16
+
17
+ // Handling 404 error
18
+ app.setNotFoundHandler((_request, reply) => {
19
+ response({
20
+ error: true,
21
+ message: 'This route does not exists',
22
+ reply,
23
+ status: 404
24
+ })
25
+ })
26
+ app.setErrorHandler<HttpError>((error, _request, reply) => {
27
+ response({
28
+ error: true,
29
+ message: error.message,
30
+ reply,
31
+ status: error.status ?? 500
32
+ })
33
+ })
34
+ }
35
+
36
+ export { applyRoutes }