temba 0.17.0 → 0.19.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 (215) hide show
  1. package/README.md +58 -10
  2. package/package.json +17 -17
  3. package/{config → src/config}/index.d.ts +15 -8
  4. package/src/config/index.d.ts.map +1 -0
  5. package/{config → src/config}/index.js +23 -28
  6. package/src/config/index.js.map +1 -0
  7. package/src/delay/delayMiddleware.d.ts +3 -0
  8. package/src/delay/delayMiddleware.d.ts.map +1 -0
  9. package/src/delay/delayMiddleware.js +13 -0
  10. package/src/delay/delayMiddleware.js.map +1 -0
  11. package/src/index.d.ts +6 -0
  12. package/src/index.d.ts.map +1 -0
  13. package/src/index.js +83 -0
  14. package/src/index.js.map +1 -0
  15. package/src/queries/in-memory.d.ts +3 -0
  16. package/src/queries/in-memory.d.ts.map +1 -0
  17. package/src/queries/in-memory.js +61 -0
  18. package/src/queries/in-memory.js.map +1 -0
  19. package/src/queries/mongo.d.ts +3 -0
  20. package/src/queries/mongo.d.ts.map +1 -0
  21. package/src/queries/mongo.js +75 -0
  22. package/src/queries/mongo.js.map +1 -0
  23. package/src/queries/queries.d.ts +2 -0
  24. package/src/queries/queries.d.ts.map +1 -0
  25. package/src/queries/queries.js +10 -0
  26. package/src/queries/queries.js.map +1 -0
  27. package/src/queries/types.d.ts +15 -0
  28. package/src/queries/types.d.ts.map +1 -0
  29. package/src/queries/types.js +2 -0
  30. package/src/queries/types.js.map +1 -0
  31. package/src/requestBodyInterceptor/interceptRequestBody.d.ts +3 -0
  32. package/src/requestBodyInterceptor/interceptRequestBody.d.ts.map +1 -0
  33. package/src/requestBodyInterceptor/interceptRequestBody.js +14 -0
  34. package/src/requestBodyInterceptor/interceptRequestBody.js.map +1 -0
  35. package/src/requestBodyInterceptor/types.d.ts +12 -0
  36. package/src/requestBodyInterceptor/types.d.ts.map +1 -0
  37. package/src/requestBodyInterceptor/types.js +2 -0
  38. package/src/requestBodyInterceptor/types.js.map +1 -0
  39. package/src/requestHandlers/delete.d.ts +12 -0
  40. package/src/requestHandlers/delete.d.ts.map +1 -0
  41. package/src/requestHandlers/delete.js +22 -0
  42. package/src/requestHandlers/delete.js.map +1 -0
  43. package/src/requestHandlers/get.d.ts +22 -0
  44. package/src/requestHandlers/get.d.ts.map +1 -0
  45. package/src/requestHandlers/get.js +47 -0
  46. package/src/requestHandlers/get.js.map +1 -0
  47. package/src/requestHandlers/index.d.ts +54 -0
  48. package/src/requestHandlers/index.d.ts.map +1 -0
  49. package/src/requestHandlers/index.js +21 -0
  50. package/src/requestHandlers/index.js.map +1 -0
  51. package/src/requestHandlers/patch.d.ts +9 -0
  52. package/src/requestHandlers/patch.d.ts.map +1 -0
  53. package/src/requestHandlers/patch.js +35 -0
  54. package/src/requestHandlers/patch.js.map +1 -0
  55. package/src/requestHandlers/post.d.ts +18 -0
  56. package/src/requestHandlers/post.d.ts.map +1 -0
  57. package/src/requestHandlers/post.js +37 -0
  58. package/src/requestHandlers/post.js.map +1 -0
  59. package/src/requestHandlers/put.d.ts +9 -0
  60. package/src/requestHandlers/put.d.ts.map +1 -0
  61. package/src/requestHandlers/put.js +35 -0
  62. package/src/requestHandlers/put.js.map +1 -0
  63. package/src/requestHandlers/types.d.ts +38 -0
  64. package/src/requestHandlers/types.d.ts.map +1 -0
  65. package/src/requestHandlers/types.js +2 -0
  66. package/src/requestHandlers/types.js.map +1 -0
  67. package/src/requestHandlers/utils.d.ts +2 -0
  68. package/src/requestHandlers/utils.d.ts.map +1 -0
  69. package/src/requestHandlers/utils.js +6 -0
  70. package/src/requestHandlers/utils.js.map +1 -0
  71. package/src/resourceRouter.d.ts +5 -0
  72. package/src/resourceRouter.d.ts.map +1 -0
  73. package/src/resourceRouter.js +95 -0
  74. package/src/resourceRouter.js.map +1 -0
  75. package/src/responseBodyInterceptor/interceptResponseBody.d.ts +3 -0
  76. package/src/responseBodyInterceptor/interceptResponseBody.d.ts.map +1 -0
  77. package/src/responseBodyInterceptor/interceptResponseBody.js +7 -0
  78. package/src/responseBodyInterceptor/interceptResponseBody.js.map +1 -0
  79. package/src/responseBodyInterceptor/types.d.ts +11 -0
  80. package/src/responseBodyInterceptor/types.d.ts.map +1 -0
  81. package/src/responseBodyInterceptor/types.js +2 -0
  82. package/src/responseBodyInterceptor/types.js.map +1 -0
  83. package/src/schema/compile.d.ts +3 -0
  84. package/src/schema/compile.d.ts.map +1 -0
  85. package/src/schema/compile.js +26 -0
  86. package/src/schema/compile.js.map +1 -0
  87. package/src/schema/types.d.ts +25 -0
  88. package/src/schema/types.d.ts.map +1 -0
  89. package/src/schema/types.js +2 -0
  90. package/{routes → src/schema}/types.js.map +1 -1
  91. package/src/schema/validate.d.ts +4 -0
  92. package/src/schema/validate.d.ts.map +1 -0
  93. package/src/schema/validate.js +14 -0
  94. package/src/schema/validate.js.map +1 -0
  95. package/src/urls/urlParser.d.ts +5 -0
  96. package/src/urls/urlParser.d.ts.map +1 -0
  97. package/src/urls/urlParser.js +9 -0
  98. package/src/urls/urlParser.js.map +1 -0
  99. package/test/integration/api-prefix.test.d.ts +2 -0
  100. package/test/integration/api-prefix.test.d.ts.map +1 -0
  101. package/test/integration/api-prefix.test.js +69 -0
  102. package/test/integration/api-prefix.test.js.map +1 -0
  103. package/test/integration/createServer.d.ts +4 -0
  104. package/test/integration/createServer.d.ts.map +1 -0
  105. package/test/integration/createServer.js +4 -0
  106. package/test/integration/createServer.js.map +1 -0
  107. package/test/integration/crud.test.d.ts +2 -0
  108. package/test/integration/crud.test.d.ts.map +1 -0
  109. package/test/integration/crud.test.js +173 -0
  110. package/test/integration/crud.test.js.map +1 -0
  111. package/test/integration/custom-router.test.d.ts +2 -0
  112. package/test/integration/custom-router.test.d.ts.map +1 -0
  113. package/test/integration/custom-router.test.js +74 -0
  114. package/test/integration/custom-router.test.js.map +1 -0
  115. package/test/integration/head-method.test.d.ts +2 -0
  116. package/test/integration/head-method.test.d.ts.map +1 -0
  117. package/test/integration/head-method.test.js +38 -0
  118. package/test/integration/head-method.test.js.map +1 -0
  119. package/test/integration/options-method.test.d.ts +2 -0
  120. package/test/integration/options-method.test.d.ts.map +1 -0
  121. package/test/integration/options-method.test.js +30 -0
  122. package/test/integration/options-method.test.js.map +1 -0
  123. package/test/integration/requestBodyInterceptor/requestBodyInterceptor-change-requestBody.test.d.ts +2 -0
  124. package/test/integration/requestBodyInterceptor/requestBodyInterceptor-change-requestBody.test.d.ts.map +1 -0
  125. package/test/integration/requestBodyInterceptor/requestBodyInterceptor-change-requestBody.test.js +76 -0
  126. package/test/integration/requestBodyInterceptor/requestBodyInterceptor-change-requestBody.test.js.map +1 -0
  127. package/test/integration/requestBodyInterceptor/requestBodyInterceptor-error-string.test.d.ts +2 -0
  128. package/test/integration/requestBodyInterceptor/requestBodyInterceptor-error-string.test.d.ts.map +1 -0
  129. package/test/integration/requestBodyInterceptor/requestBodyInterceptor-error-string.test.js +60 -0
  130. package/test/integration/requestBodyInterceptor/requestBodyInterceptor-error-string.test.js.map +1 -0
  131. package/test/integration/requestBodyInterceptor/requestBodyInterceptor-invalid-return-types.test.d.ts +2 -0
  132. package/test/integration/requestBodyInterceptor/requestBodyInterceptor-invalid-return-types.test.d.ts.map +1 -0
  133. package/test/integration/requestBodyInterceptor/requestBodyInterceptor-invalid-return-types.test.js +89 -0
  134. package/test/integration/requestBodyInterceptor/requestBodyInterceptor-invalid-return-types.test.js.map +1 -0
  135. package/test/integration/requestBodyInterceptor/requestBodyInterceptor-void.test.d.ts +2 -0
  136. package/test/integration/requestBodyInterceptor/requestBodyInterceptor-void.test.d.ts.map +1 -0
  137. package/test/integration/requestBodyInterceptor/requestBodyInterceptor-void.test.js +47 -0
  138. package/test/integration/requestBodyInterceptor/requestBodyInterceptor-void.test.js.map +1 -0
  139. package/test/integration/responseBodyInterceptor.test.d.ts +2 -0
  140. package/test/integration/responseBodyInterceptor.test.d.ts.map +1 -0
  141. package/test/integration/responseBodyInterceptor.test.js +107 -0
  142. package/test/integration/responseBodyInterceptor.test.js.map +1 -0
  143. package/test/integration/returnNullFields.test.d.ts +2 -0
  144. package/test/integration/returnNullFields.test.d.ts.map +1 -0
  145. package/test/integration/returnNullFields.test.js +51 -0
  146. package/test/integration/returnNullFields.test.js.map +1 -0
  147. package/test/integration/root-url.test.d.ts +2 -0
  148. package/test/integration/root-url.test.d.ts.map +1 -0
  149. package/test/integration/root-url.test.js +29 -0
  150. package/test/integration/root-url.test.js.map +1 -0
  151. package/test/integration/schema-validation.test.d.ts +2 -0
  152. package/test/integration/schema-validation.test.d.ts.map +1 -0
  153. package/test/integration/schema-validation.test.js +169 -0
  154. package/test/integration/schema-validation.test.js.map +1 -0
  155. package/test/unit/config/config.test.d.ts +2 -0
  156. package/test/unit/config/config.test.d.ts.map +1 -0
  157. package/test/unit/config/config.test.js +121 -0
  158. package/test/unit/config/config.test.js.map +1 -0
  159. package/test/unit/urls/urlParser.test.d.ts +2 -0
  160. package/test/unit/urls/urlParser.test.d.ts.map +1 -0
  161. package/test/unit/urls/urlParser.test.js +43 -0
  162. package/test/unit/urls/urlParser.test.js.map +1 -0
  163. package/tsconfig.tsbuildinfo +1 -0
  164. package/vitest.config.d.ts +3 -0
  165. package/vitest.config.d.ts.map +1 -0
  166. package/vitest.config.js +10 -0
  167. package/vitest.config.js.map +1 -0
  168. package/config/index.js.map +0 -1
  169. package/delay/delayMiddleware.d.ts +0 -2
  170. package/delay/delayMiddleware.js +0 -16
  171. package/delay/delayMiddleware.js.map +0 -1
  172. package/index.d.ts +0 -5
  173. package/index.js +0 -94
  174. package/index.js.map +0 -1
  175. package/queries/in-memory.d.ts +0 -19
  176. package/queries/in-memory.js +0 -66
  177. package/queries/in-memory.js.map +0 -1
  178. package/queries/mongo.d.ts +0 -19
  179. package/queries/mongo.js +0 -106
  180. package/queries/mongo.js.map +0 -1
  181. package/queries/queries.d.ts +0 -20
  182. package/queries/queries.js +0 -17
  183. package/queries/queries.js.map +0 -1
  184. package/routes/delete.d.ts +0 -4
  185. package/routes/delete.js +0 -39
  186. package/routes/delete.js.map +0 -1
  187. package/routes/get.d.ts +0 -4
  188. package/routes/get.js +0 -71
  189. package/routes/get.js.map +0 -1
  190. package/routes/interceptors.d.ts +0 -3
  191. package/routes/interceptors.js +0 -22
  192. package/routes/interceptors.js.map +0 -1
  193. package/routes/patch.d.ts +0 -4
  194. package/routes/patch.js +0 -47
  195. package/routes/patch.js.map +0 -1
  196. package/routes/post.d.ts +0 -4
  197. package/routes/post.js +0 -47
  198. package/routes/post.js.map +0 -1
  199. package/routes/put.d.ts +0 -4
  200. package/routes/put.js +0 -47
  201. package/routes/put.js.map +0 -1
  202. package/routes/routes.d.ts +0 -6
  203. package/routes/routes.js +0 -61
  204. package/routes/routes.js.map +0 -1
  205. package/routes/types.d.ts +0 -17
  206. package/routes/types.js +0 -3
  207. package/routes/utils.d.ts +0 -3
  208. package/routes/utils.js +0 -8
  209. package/routes/utils.js.map +0 -1
  210. package/urls/urlMiddleware.d.ts +0 -3
  211. package/urls/urlMiddleware.js +0 -30
  212. package/urls/urlMiddleware.js.map +0 -1
  213. package/urls/urlParser.d.ts +0 -5
  214. package/urls/urlParser.js +0 -13
  215. package/urls/urlParser.js.map +0 -1
package/README.md CHANGED
@@ -109,15 +109,17 @@ The HTTP methods that are supported are `GET`, `POST`, `PATCH`, `PUT`, `DELETE`,
109
109
 
110
110
  On the root URI (e.g. http://localhost:8080/) only a `GET` request is supported, which shows you a message indicating the API is working. All other HTTP methods on the root URI return a `405 Method Not Allowed` response.
111
111
 
112
+ The `OPTIONS` method also works, but because Temba uses Express' default implementation for that, the `Access-Control-Allow-Methods` response header might not always be correct.
113
+
112
114
  ### JSON
113
115
 
114
116
  Temba supports JSON only.
115
117
 
116
118
  Request bodies sent with a `POST`, `PATCH`, and `PUT` requests are valid when the request body is either empty, or when it's valid formatted JSON. Adding a `Content-Type: application/json` header is required. If you send a request with invalid formatted JSON, a `400 Bad Request` response is returned.
117
119
 
118
- Any valid formatted JSON is accepted and stored. If you want to validate or even change the JSON in the request bodies, check out the [`requestBodyInterceptor`](#request-body-validation-or-mutation) callbacks.
120
+ Any valid formatted JSON is accepted and stored. If you want to validate or even change the JSON in the request bodies, check out [JSON Schema request body validation](#json-schema-request-body-validation) and the [`requestBodyInterceptor`](#request-body-validation-or-mutation).
119
121
 
120
- IDs are auto generated when creating resources. IDs in the JSON request body are ignored for any request.
122
+ IDs are auto generated when creating resources. IDs in the JSON request body are always ignored.
121
123
 
122
124
  ## Usage
123
125
 
@@ -149,7 +151,7 @@ Requests on these resources only give a `404 Not Found` if the ID does not exist
149
151
 
150
152
  ### Static assets
151
153
 
152
- If you want to host static assets, next to the API, configure the `staticFolder`:
154
+ If you want to host static assets, for example next to the API, a web app consuming it, you can configure a `staticFolder`:
153
155
 
154
156
  ```js
155
157
  const config = {
@@ -160,8 +162,6 @@ const server = temba.create(config)
160
162
 
161
163
  With this setting, sending a `GET` request to the root URL, returns the content that is in the `'./build'` folder in your project.
162
164
 
163
- This way, you could create an API, and the web app consuming it, in one project.
164
-
165
165
  Without configuring a `staticFolder`, a `GET` to the root URL returns `"It works! ツ"`. When the `staticFolder` is configured, it returns whatever is in the `build` folder in your project, for example an HTML page.
166
166
 
167
167
  However, this might cause conflicts between the API resources and the web app routes: If the web app in the `build` folder has a route to `/products`, but there is also a `/products` API resource, the web app route is returned.
@@ -185,9 +185,9 @@ After configuring the `apiPrefix`, requests to the root URL (e.g. http://localho
185
185
 
186
186
  However, if you configured both an `apiPrefix` and a `staticFolder`, a `GET` on the root URL will return the content in the `staticFolder`.
187
187
 
188
- ### Request body validation or mutation
188
+ ### JSON Schema request body validation
189
189
 
190
- Temba does not validate request bodies.
190
+ By default, Temba does not validate request bodies.
191
191
 
192
192
  This means you can store your resources in any format you like. So creating the following two (very different) _movies_ is perfectly fine:
193
193
 
@@ -205,7 +205,43 @@ POST /movies
205
205
  }
206
206
  ```
207
207
 
208
- You can even omit a request body when doing a `POST`, `PATCH`, or `PUT`. If you don't want that, and want to have proper validation, use the `requestBodyInterceptor` config setting:
208
+ You can even omit a request body when doing a `POST`, `PATCH`, or `PUT`. While this might be fine or even convenient when using Temba for prototyping, at some some point you might want to validate the request body.
209
+
210
+ With the `schema` setting, you can define a [JSON Schema](https://json-schema.org/), per resource, and per request method. Here we define that when creating or replacing a movie, the `title` is required, the `description` is optional, and we don't allow any other fields. Updating movies has the same schema, except there are no required fields:
211
+
212
+ ```js
213
+ const schemaNewMovie = {
214
+ type: 'object',
215
+ properties: {
216
+ title: { type: 'string' },
217
+ description: { type: 'string' },
218
+ },
219
+ required: ['title'],
220
+ additionalProperties: false,
221
+ }
222
+
223
+ const schemaUpdateMovie = { ...schemaNewMovie, required: [] }
224
+
225
+ const config = {
226
+ schema: {
227
+ movies: {
228
+ post: schemaNewMovie,
229
+ put: schemaNewMovie,
230
+ patch: schemaUpdateMovie,
231
+ },
232
+ },
233
+ }
234
+
235
+ const server = temba.create(config)
236
+ ```
237
+
238
+ If a request is not valid according to the schema, a `400 Bad Request` response is returned, and a message in the response body indicating the validation error.
239
+
240
+ ### Intercepting requests
241
+
242
+ In addition to (or instead of) validating the request using JSON Schema, you can also intercept the request body before it goes to the database, using the `requestBodyInterceptor` setting.
243
+
244
+ It allows you to implement your own validation, or even change the request body.
209
245
 
210
246
  ```js
211
247
  const config = {
@@ -241,7 +277,7 @@ Example:
241
277
  const config = {
242
278
  requestBodyInterceptor: {
243
279
  post: ({ resource, body }) => {
244
- // Do not allow Pokemons to be created: 400 Bad Req best
280
+ // Do not allow Pokemons to be created: 400 Bad Request
245
281
  if (resource === 'pokemons') return 'You are not allowed to create new Pokemons'
246
282
 
247
283
  // Add a genre to Star Trek films:
@@ -388,6 +424,17 @@ const config = {
388
424
  // Change the response body before it is sent to the client
389
425
  },
390
426
  returnNullFields: false,
427
+ schema: {
428
+ movies: {
429
+ post: {
430
+ type: 'object',
431
+ properties: {
432
+ title: { type: 'string' },
433
+ },
434
+ required: ['title'],
435
+ },
436
+ },
437
+ },
391
438
  staticFolder: 'build',
392
439
  }
393
440
  const server = temba.create(config)
@@ -407,6 +454,7 @@ These are all the possible settings:
407
454
  | `resources` | See [Allowing specific resources only](#allowing-specific-resources-only) | `[]` |
408
455
  | `responseBodyInterceptor` | See [Response body interception](#request-body-validation-or-mutation) | `noop` |
409
456
  | `returnNullFields` | Whether fields with a `null` value should be returned in responses. | `true` |
457
+ | `schema` | See [JSON Schema request body validation](#json-schema-request-body-validation) | `null` |
410
458
  | `staticFolder` | See [Static assets](#static-assets) | `null` |
411
459
 
412
460
  ## Roadmap
@@ -425,7 +473,7 @@ Although I won't promise if and when, these are some things to consider for the
425
473
 
426
474
  ## Under the hood
427
475
 
428
- Temba is built with JavaScript, [Node](https://nodejs.org), [Express](https://expressjs.com/), [Jest](https://jestjs.io/), [Supertest](https://www.npmjs.com/package/supertest), and [@rakered/mongo](https://www.npmjs.com/package/@rakered/mongo).
476
+ Temba is built with JavaScript, [Node](https://nodejs.org), [Express](https://expressjs.com/), [Vitest](https://vitest.dev/), [Supertest](https://www.npmjs.com/package/supertest), and [@rakered/mongo](https://www.npmjs.com/package/@rakered/mongo).
429
477
 
430
478
  ## Contributors ✨
431
479
 
package/package.json CHANGED
@@ -1,12 +1,13 @@
1
1
  {
2
2
  "name": "temba",
3
- "version": "0.17.0",
3
+ "version": "0.19.0",
4
4
  "description": "Get a simple MongoDB REST API with zero coding in less than 30 seconds (seriously).",
5
+ "type": "module",
5
6
  "main": "dist/index.js",
6
7
  "scripts": {
7
8
  "build": "rm -rf dist && tsc && cp package.json README.md ./dist",
8
- "test": "jest --silent --no-cache",
9
- "test:watch": "jest --watch --no-cache",
9
+ "test": "vitest",
10
+ "test:watch": "vitest --watch",
10
11
  "lint": "eslint --ignore-path .gitignore --ext .js,.ts .",
11
12
  "format": "prettier --ignore-path .gitignore --write \"**/*.+(js|ts|json)\""
12
13
  },
@@ -18,24 +19,23 @@
18
19
  "author": "Bouwe (https://bouwe.io)",
19
20
  "license": "ISC",
20
21
  "devDependencies": {
21
- "@types/cors": "^2.8.13",
22
- "@types/express": "^4.17.17",
23
- "@types/jest": "^29.5.3",
24
- "@types/morgan": "^1.9.4",
25
- "@types/supertest": "^2.0.12",
26
- "@typescript-eslint/eslint-plugin": "^6.0.0",
27
- "@typescript-eslint/parser": "^6.0.0",
28
- "eslint": "^8.45.0",
29
- "eslint-config-prettier": "^8.8.0",
30
- "jest": "^29.6.1",
31
- "jest-extended": "^4.0.0",
32
- "prettier": "^3.0.0",
22
+ "@types/cors": "^2.8.15",
23
+ "@types/express": "^4.17.20",
24
+ "@types/morgan": "^1.9.8",
25
+ "@types/supertest": "^2.0.15",
26
+ "@typescript-eslint/eslint-plugin": "^6.10.0",
27
+ "@typescript-eslint/parser": "^6.10.0",
28
+ "eslint": "^8.53.0",
29
+ "eslint-config-prettier": "^9.0.0",
30
+ "prettier": "^3.0.3",
33
31
  "supertest": "^6.3.3",
34
- "ts-jest": "^29.1.1",
35
- "typescript": "^5.1.6"
32
+ "ts-node": "^10.9.1",
33
+ "typescript": "^5.2.2",
34
+ "vitest": "^1.3.1"
36
35
  },
37
36
  "dependencies": {
38
37
  "@rakered/mongo": "^1.6.0",
38
+ "ajv": "^8.12.0",
39
39
  "connect-pause": "^0.1.0",
40
40
  "cors": "^2.8.5",
41
41
  "express": "^4.18.2",
@@ -1,20 +1,24 @@
1
1
  import { Router } from 'express';
2
- import { RequestBodyInterceptor, ResponseBodyInterceptor } from '../routes/types';
2
+ import type { ConfiguredSchemas } from '../schema/types';
3
+ import { RequestBodyInterceptor } from '../requestBodyInterceptor/types';
4
+ import { ResponseBodyInterceptor } from '../responseBodyInterceptor/types';
3
5
  export type Config = {
4
6
  validateResources: boolean;
5
7
  resources: string[];
6
- apiPrefix: string;
8
+ apiPrefix: string | null;
7
9
  cacheControl: string;
8
- requestBodyInterceptor: RequestBodyInterceptor;
9
- responseBodyInterceptor: ResponseBodyInterceptor;
10
- staticFolder: string;
11
- connectionString: string;
10
+ requestBodyInterceptor: RequestBodyInterceptor | null;
11
+ responseBodyInterceptor: ResponseBodyInterceptor | null;
12
+ staticFolder: string | null;
13
+ connectionString: string | null;
12
14
  delay: number;
13
- customRouter: Router;
15
+ customRouter: Router | null;
14
16
  returnNullFields: boolean;
15
17
  isTesting: boolean;
16
18
  port: number;
19
+ schemas: ConfiguredSchemas | null;
17
20
  };
21
+ export type ConfigKey = keyof Config;
18
22
  export type RouterConfig = Pick<Config, 'validateResources' | 'resources' | 'apiPrefix' | 'cacheControl' | 'requestBodyInterceptor' | 'responseBodyInterceptor' | 'returnNullFields'>;
19
23
  export type UserConfig = {
20
24
  resources?: string[];
@@ -29,5 +33,8 @@ export type UserConfig = {
29
33
  returnNullFields?: boolean;
30
34
  isTesting?: boolean;
31
35
  port?: number;
36
+ schemas?: ConfiguredSchemas;
32
37
  };
33
- export declare function initConfig(userConfig: UserConfig): Config;
38
+ export declare const initConfig: (userConfig?: UserConfig) => Config;
39
+ export declare const isUndefined: (value: unknown) => value is undefined;
40
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/config/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAA;AAChC,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAA;AACxD,OAAO,EAAE,sBAAsB,EAAE,MAAM,iCAAiC,CAAA;AACxE,OAAO,EAAE,uBAAuB,EAAE,MAAM,kCAAkC,CAAA;AAE1E,MAAM,MAAM,MAAM,GAAG;IACnB,iBAAiB,EAAE,OAAO,CAAA;IAC1B,SAAS,EAAE,MAAM,EAAE,CAAA;IACnB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAA;IACxB,YAAY,EAAE,MAAM,CAAA;IACpB,sBAAsB,EAAE,sBAAsB,GAAG,IAAI,CAAA;IACrD,uBAAuB,EAAE,uBAAuB,GAAG,IAAI,CAAA;IACvD,YAAY,EAAE,MAAM,GAAG,IAAI,CAAA;IAC3B,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAA;IAC/B,KAAK,EAAE,MAAM,CAAA;IACb,YAAY,EAAE,MAAM,GAAG,IAAI,CAAA;IAC3B,gBAAgB,EAAE,OAAO,CAAA;IACzB,SAAS,EAAE,OAAO,CAAA;IAClB,IAAI,EAAE,MAAM,CAAA;IACZ,OAAO,EAAE,iBAAiB,GAAG,IAAI,CAAA;CAClC,CAAA;AAED,MAAM,MAAM,SAAS,GAAG,MAAM,MAAM,CAAA;AAEpC,MAAM,MAAM,YAAY,GAAG,IAAI,CAC7B,MAAM,EACJ,mBAAmB,GACnB,WAAW,GACX,WAAW,GACX,cAAc,GACd,wBAAwB,GACxB,yBAAyB,GACzB,kBAAkB,CACrB,CAAA;AAED,MAAM,MAAM,UAAU,GAAG;IACvB,SAAS,CAAC,EAAE,MAAM,EAAE,CAAA;IACpB,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,gBAAgB,CAAC,EAAE,MAAM,CAAA;IACzB,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,sBAAsB,CAAC,EAAE,sBAAsB,CAAA;IAC/C,uBAAuB,CAAC,EAAE,uBAAuB,CAAA;IACjD,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,gBAAgB,CAAC,EAAE,OAAO,CAAA;IAC1B,SAAS,CAAC,EAAE,OAAO,CAAA;IACnB,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,OAAO,CAAC,EAAE,iBAAiB,CAAA;CAC5B,CAAA;AAmBD,eAAO,MAAM,UAAU,gBAAiB,UAAU,KAAG,MAoFpD,CAAA;AAED,eAAO,MAAM,WAAW,UAAW,OAAO,uBAAqD,CAAA"}
@@ -1,38 +1,23 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.initConfig = void 0;
4
1
  const defaultConfig = {
5
2
  resources: [],
6
3
  validateResources: false,
7
4
  staticFolder: null,
8
- apiPrefix: '',
5
+ apiPrefix: null,
9
6
  connectionString: null,
10
7
  cacheControl: 'no-store',
11
8
  delay: 0,
12
- requestBodyInterceptor: {
13
- post: () => {
14
- // do nothing
15
- },
16
- patch: () => {
17
- // do nothing
18
- },
19
- put: () => {
20
- // do nothing
21
- },
22
- },
23
- responseBodyInterceptor: ({ body }) => {
24
- return body;
25
- },
9
+ requestBodyInterceptor: null,
10
+ responseBodyInterceptor: null,
26
11
  customRouter: null,
27
12
  returnNullFields: true,
28
13
  isTesting: false,
29
14
  port: 3000,
15
+ schemas: null,
30
16
  };
31
- function initConfig(userConfig) {
32
- var _a, _b, _c;
17
+ export const initConfig = (userConfig) => {
33
18
  if (!userConfig)
34
19
  return defaultConfig;
35
- const config = Object.assign({}, defaultConfig);
20
+ const config = { ...defaultConfig };
36
21
  if (userConfig.resources && userConfig.resources.length > 0) {
37
22
  config.resources = userConfig.resources;
38
23
  config.validateResources = true;
@@ -53,10 +38,11 @@ function initConfig(userConfig) {
53
38
  userConfig.delay !== 0 &&
54
39
  typeof Number(userConfig.delay) === 'number' &&
55
40
  Number(userConfig.delay) > 0 &&
56
- Number(userConfig.delay) < 10000) {
57
- config.delay = Number(userConfig.delay);
41
+ Number(userConfig.delay) < 100000) {
42
+ config.delay = userConfig.delay;
58
43
  }
59
44
  if (userConfig.requestBodyInterceptor) {
45
+ config.requestBodyInterceptor = config.requestBodyInterceptor || {};
60
46
  if (userConfig.requestBodyInterceptor.post &&
61
47
  typeof userConfig.requestBodyInterceptor.post === 'function') {
62
48
  config.requestBodyInterceptor.post = userConfig.requestBodyInterceptor.post;
@@ -76,10 +62,19 @@ function initConfig(userConfig) {
76
62
  if (userConfig.customRouter) {
77
63
  config.customRouter = userConfig.customRouter;
78
64
  }
79
- config.returnNullFields = (_a = userConfig.returnNullFields) !== null && _a !== void 0 ? _a : true;
80
- config.isTesting = (_b = userConfig.isTesting) !== null && _b !== void 0 ? _b : false;
81
- config.port = (_c = userConfig.port) !== null && _c !== void 0 ? _c : 3000;
65
+ if (!isUndefined(userConfig.returnNullFields)) {
66
+ config.returnNullFields = userConfig.returnNullFields;
67
+ }
68
+ if (!isUndefined(userConfig.isTesting)) {
69
+ config.isTesting = userConfig.isTesting;
70
+ }
71
+ if (!isUndefined(userConfig.port)) {
72
+ config.port = userConfig.port;
73
+ }
74
+ if (userConfig.schemas) {
75
+ config.schemas = userConfig.schemas;
76
+ }
82
77
  return config;
83
- }
84
- exports.initConfig = initConfig;
78
+ };
79
+ export const isUndefined = (value) => typeof value === 'undefined';
85
80
  //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/config/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import type { NextFunction, Request, Response } from 'express';
2
+ export declare const createDelayMiddleware: (delay: number) => (req: Request, res: Response, next: NextFunction) => void;
3
+ //# sourceMappingURL=delayMiddleware.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"delayMiddleware.d.ts","sourceRoot":"","sources":["../../../src/delay/delayMiddleware.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAA;AAQ9D,eAAO,MAAM,qBAAqB,UAAW,MAAM,WACpC,OAAO,OAAO,QAAQ,QAAQ,YAAY,SAKxD,CAAA"}
@@ -0,0 +1,13 @@
1
+ const pause = (delay) => {
2
+ return (req, res, next) => {
3
+ setTimeout(next, delay);
4
+ };
5
+ };
6
+ export const createDelayMiddleware = (delay) => {
7
+ return (req, res, next) => {
8
+ console.log('Start delay...');
9
+ pause(delay)(req, res, next);
10
+ console.log('Delay finished!');
11
+ };
12
+ };
13
+ //# sourceMappingURL=delayMiddleware.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"delayMiddleware.js","sourceRoot":"","sources":["../../../src/delay/delayMiddleware.ts"],"names":[],"mappings":"AAEA,MAAM,KAAK,GAAG,CAAC,KAAa,EAAE,EAAE;IAC9B,OAAO,CAAC,GAAY,EAAE,GAAa,EAAE,IAAkB,EAAE,EAAE;QACzD,UAAU,CAAC,IAAI,EAAE,KAAK,CAAC,CAAA;IACzB,CAAC,CAAA;AACH,CAAC,CAAA;AAED,MAAM,CAAC,MAAM,qBAAqB,GAAG,CAAC,KAAa,EAAE,EAAE;IACrD,OAAO,CAAC,GAAY,EAAE,GAAa,EAAE,IAAkB,EAAE,EAAE;QACzD,OAAO,CAAC,GAAG,CAAC,gBAAgB,CAAC,CAAA;QAC7B,KAAK,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,GAAG,EAAE,IAAI,CAAC,CAAA;QAC5B,OAAO,CAAC,GAAG,CAAC,iBAAiB,CAAC,CAAA;IAChC,CAAC,CAAA;AACH,CAAC,CAAA"}
package/src/index.d.ts ADDED
@@ -0,0 +1,6 @@
1
+ import type { UserConfig } from './config';
2
+ export declare const create: (userConfig?: UserConfig) => {
3
+ start: () => void;
4
+ Express: import("express-serve-static-core").Express | undefined;
5
+ };
6
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,UAAU,CAAA;AAiG1C,eAAO,MAAM,MAAM,gBAAiB,UAAU;;;CAA6B,CAAA"}
package/src/index.js ADDED
@@ -0,0 +1,83 @@
1
+ import express, { json } from 'express';
2
+ import morgan from 'morgan';
3
+ import { createQueries } from './queries/queries';
4
+ import { initConfig } from './config';
5
+ import cors from 'cors';
6
+ import { createDelayMiddleware } from './delay/delayMiddleware';
7
+ import { compileSchemas } from './schema/compile';
8
+ import { createResourceRouter } from './resourceRouter';
9
+ const createServer = (userConfig) => {
10
+ const config = initConfig(userConfig);
11
+ const queries = createQueries(config.connectionString);
12
+ const app = express();
13
+ app.use(json());
14
+ // Add HTTP request logging.
15
+ app.use(morgan('tiny'));
16
+ // Enable CORS for all requests.
17
+ app.use(cors({ origin: true, credentials: true }));
18
+ // Add a delay to every request, if configured.
19
+ if (config.delay > 0) {
20
+ const delayMiddleware = createDelayMiddleware(config.delay);
21
+ app.use(delayMiddleware);
22
+ }
23
+ // Serve a static folder, if configured.
24
+ if (config.staticFolder) {
25
+ app.use(express.static(config.staticFolder));
26
+ }
27
+ // On the root URL (with apiPrefix, if applicable) only a GET is allowed.
28
+ const rootRouter = express.Router();
29
+ const rootPath = config.apiPrefix ? `${config.apiPrefix}` : '/';
30
+ app.use(rootPath, rootRouter);
31
+ // Use a custom router, if configured.
32
+ if (config.customRouter) {
33
+ app.use(config.customRouter);
34
+ }
35
+ // Temba supports the GET, POST, PUT, PATCH, DELETE, and HEAD methods for resource URLs.
36
+ // HEAD is not implemented here, because Express supports it out of the box.
37
+ // Create a router on all other URLs, for all supported methods
38
+ const resourcePath = config.apiPrefix ? `${config.apiPrefix}*` : '*';
39
+ const schemas = compileSchemas(config.schemas);
40
+ const resourceRouter = createResourceRouter(queries, schemas, config);
41
+ app.use(resourcePath, resourceRouter);
42
+ // A GET to the root URL shows a default message.
43
+ rootRouter.get('/', async (_, res) => {
44
+ return res.send('It works! ツ');
45
+ });
46
+ // Route for handling not allowed methods.
47
+ const handleMethodNotAllowed = (_, res) => {
48
+ res.status(405).json({ message: 'Method Not Allowed' });
49
+ };
50
+ // Route for handling not found.
51
+ const handleNotFound = (_, res) => {
52
+ res.status(404).json({ message: 'Not Found' });
53
+ };
54
+ // All other requests to the root URL are not allowed.
55
+ rootRouter.all('/', handleMethodNotAllowed);
56
+ // In case of an API prefix, resource URLs outside of the API prefix return a 404 Not Found.
57
+ if (config.apiPrefix) {
58
+ app.get('*', handleNotFound);
59
+ app.post('*', handleNotFound);
60
+ app.put('*', handleNotFound);
61
+ app.delete('*', handleNotFound);
62
+ app.patch('*', handleNotFound);
63
+ }
64
+ // All other methods to any URL are not allowed.
65
+ app.all('*', handleMethodNotAllowed);
66
+ if (config.apiPrefix)
67
+ app.all(`${config.apiPrefix}*`, handleMethodNotAllowed);
68
+ return {
69
+ start: () => {
70
+ if (config.isTesting) {
71
+ console.log('⛔️ Server not started. Remove or disable isTesting from your config.');
72
+ return;
73
+ }
74
+ app.listen(config.port, () => {
75
+ console.log(`✅ Server listening on port ${config.port}`);
76
+ });
77
+ },
78
+ // Expose Express for testing purposes only, e.g. usage with supertest.
79
+ Express: config.isTesting ? app : undefined,
80
+ };
81
+ };
82
+ export const create = (userConfig) => createServer(userConfig);
83
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import { Queries } from './types';
2
+ export declare const inMemoryQueries: Queries;
3
+ //# sourceMappingURL=in-memory.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"in-memory.d.ts","sourceRoot":"","sources":["../../../src/queries/in-memory.ts"],"names":[],"mappings":"AAAA,OAAO,EAAuB,OAAO,EAAE,MAAM,SAAS,CAAA;AAqEtD,eAAO,MAAM,eAAe,EAAE,OAQ7B,CAAA"}
@@ -0,0 +1,61 @@
1
+ const data = {};
2
+ const getAll = (resource) => {
3
+ createResourceArrayIfNecessary(resource);
4
+ return new Promise((resolve) => {
5
+ resolve(data[resource] || []);
6
+ });
7
+ };
8
+ const getById = (resource, id) => {
9
+ createResourceArrayIfNecessary(resource);
10
+ const item = (data[resource] || []).find((item) => item.id === id) || null;
11
+ return new Promise((resolve) => {
12
+ resolve(item);
13
+ });
14
+ };
15
+ const create = (resource, item) => {
16
+ createResourceArrayIfNecessary(resource);
17
+ const newItem = { ...item, id: String(new Date().getTime()) };
18
+ data[resource] = [...(data[resource] || []), newItem];
19
+ return new Promise((resolve) => {
20
+ resolve(newItem);
21
+ });
22
+ };
23
+ const update = (resource, item) => {
24
+ createResourceArrayIfNecessary(resource);
25
+ const updatedItem = { ...item };
26
+ data[resource] = [...(data[resource] || []).filter((r) => r.id !== item.id), updatedItem];
27
+ return new Promise((resolve) => {
28
+ resolve(updatedItem);
29
+ });
30
+ };
31
+ const replace = (resource, item) => {
32
+ return update(resource, item);
33
+ };
34
+ const deleteById = (resource, id) => {
35
+ createResourceArrayIfNecessary(resource);
36
+ data[resource] = (data[resource] || []).filter((item) => item.id !== id);
37
+ return new Promise((resolve) => {
38
+ resolve();
39
+ });
40
+ };
41
+ const deleteAll = (resource) => {
42
+ createResourceArrayIfNecessary(resource);
43
+ data[resource] = [];
44
+ return new Promise((resolve) => {
45
+ resolve();
46
+ });
47
+ };
48
+ const createResourceArrayIfNecessary = (resource) => {
49
+ if (!Object.hasOwn(data, resource))
50
+ data[resource] = [];
51
+ };
52
+ export const inMemoryQueries = {
53
+ getAll,
54
+ getById,
55
+ create,
56
+ update,
57
+ replace,
58
+ deleteById,
59
+ deleteAll,
60
+ };
61
+ //# sourceMappingURL=in-memory.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"in-memory.js","sourceRoot":"","sources":["../../../src/queries/in-memory.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import { Queries } from './types';
2
+ export declare const createMongoQueries: (connectionString: string) => Queries;
3
+ //# sourceMappingURL=mongo.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mongo.d.ts","sourceRoot":"","sources":["../../../src/queries/mongo.ts"],"names":[],"mappings":"AACA,OAAO,EAAuB,OAAO,EAAE,MAAM,SAAS,CAAA;AA8FtD,eAAO,MAAM,kBAAkB,qBAAsB,MAAM,YAc1D,CAAA"}
@@ -0,0 +1,75 @@
1
+ import { connect } from '@rakered/mongo';
2
+ let uri;
3
+ let db;
4
+ const connectToDatabase = async () => {
5
+ if (!db) {
6
+ console.log('Connecting to MongoDB...');
7
+ try {
8
+ db = await connect(uri);
9
+ console.log('Connected to MongoDB!');
10
+ }
11
+ catch (error) {
12
+ console.log('Error connecting to MongoDB:');
13
+ console.error(error);
14
+ }
15
+ }
16
+ };
17
+ const getAll = async (resource) => {
18
+ await connectToDatabase();
19
+ const items = (await db[resource].find({}));
20
+ if (!items)
21
+ return [];
22
+ return items.map((item) => removeUnderscoreFromId(item));
23
+ };
24
+ const getById = async (resource, id) => {
25
+ await connectToDatabase();
26
+ const item = await db[resource].findOne({ _id: id });
27
+ if (!item)
28
+ return null;
29
+ return removeUnderscoreFromId(item);
30
+ };
31
+ const create = async (resource, item) => {
32
+ await connectToDatabase();
33
+ const createdItem = await db[resource].insertOne(item);
34
+ return removeUnderscoreFromId(createdItem.ops[0]);
35
+ };
36
+ const update = async (resource, item) => {
37
+ await connectToDatabase();
38
+ const { id, ...itemWithoutId } = item;
39
+ const updatedItem = await db[resource].findOneAndUpdate({ _id: id }, { $set: itemWithoutId }, { returnOriginal: false });
40
+ return removeUnderscoreFromId(updatedItem.value);
41
+ };
42
+ const replace = async (resource, item) => {
43
+ await connectToDatabase();
44
+ const { id, ...itemWithoutId } = item;
45
+ const replacedItem = await db[resource].findOneAndReplace({ _id: id }, itemWithoutId, {
46
+ returnOriginal: false,
47
+ });
48
+ return removeUnderscoreFromId(replacedItem.value);
49
+ };
50
+ const deleteById = async (resource, id) => {
51
+ await connectToDatabase();
52
+ await db[resource].deleteOne({ _id: id });
53
+ };
54
+ const deleteAll = async (resource) => {
55
+ await connectToDatabase();
56
+ await db[resource].deleteMany({});
57
+ };
58
+ const removeUnderscoreFromId = (item) => {
59
+ const { _id, ...updatedItem } = item;
60
+ return updatedItem;
61
+ };
62
+ export const createMongoQueries = (connectionString) => {
63
+ uri = connectionString;
64
+ const mongoQueries = {
65
+ getAll,
66
+ getById,
67
+ create,
68
+ update,
69
+ replace,
70
+ deleteById,
71
+ deleteAll,
72
+ };
73
+ return mongoQueries;
74
+ };
75
+ //# sourceMappingURL=mongo.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mongo.js","sourceRoot":"","sources":["../../../src/queries/mongo.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export declare const createQueries: (connectionString: string | null) => import("./types").Queries;
2
+ //# sourceMappingURL=queries.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"queries.d.ts","sourceRoot":"","sources":["../../../src/queries/queries.ts"],"names":[],"mappings":"AAGA,eAAO,MAAM,aAAa,qBAAsB,MAAM,GAAG,IAAI,8BAO5D,CAAA"}