sleepy-serv 0.2.1 → 0.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +80 -6
- package/package.json +1 -1
- package/src/index.js +15 -13
- package/src/middleware.js +5 -5
package/README.md
CHANGED
|
@@ -73,11 +73,19 @@ The route's logic is implemented in the route definition files. These must `expo
|
|
|
73
73
|
Here's an example of a simple handler function:
|
|
74
74
|
|
|
75
75
|
```js
|
|
76
|
-
export default function (req) {
|
|
76
|
+
export default function (req, res) {
|
|
77
|
+
console.log('res:', res)
|
|
78
|
+
|
|
77
79
|
return new Response('Hello world')
|
|
78
80
|
}
|
|
79
81
|
```
|
|
80
82
|
|
|
83
|
+
These functions take two parameters:
|
|
84
|
+
- `req`: a `BunRequest` object
|
|
85
|
+
- `res`: a results object
|
|
86
|
+
|
|
87
|
+
The `res` parameter might seem familiar if coming from ExpressJS, but this parameter has a different purpose. The `res` parameter is meant to act as a dedicated, persistent object that middleware can write their results to. This way, the `req` object stays as a lean `BunRequest`.
|
|
88
|
+
|
|
81
89
|
These handlers can also be `async` functions and `sleepy-serv` will wait for them to finish before moving on.
|
|
82
90
|
|
|
83
91
|
### Middleware
|
|
@@ -86,13 +94,13 @@ As mentioned earlier, method definition files can also export an array of functi
|
|
|
86
94
|
|
|
87
95
|
```js
|
|
88
96
|
export default [
|
|
89
|
-
async req => {
|
|
90
|
-
|
|
97
|
+
async (req, res) => {
|
|
98
|
+
res.body = await req.json()
|
|
91
99
|
},
|
|
92
|
-
req => {
|
|
93
|
-
console.log('JSON body:',
|
|
100
|
+
(req, res) => {
|
|
101
|
+
console.log('JSON body:', res.body)
|
|
94
102
|
|
|
95
|
-
return new Response('Hello world'
|
|
103
|
+
return new Response('Hello world')
|
|
96
104
|
},
|
|
97
105
|
]
|
|
98
106
|
```
|
|
@@ -219,6 +227,72 @@ The middleware defined in `/api/users/:userId/meta.js` will be applied the follo
|
|
|
219
227
|
|
|
220
228
|
At the time of this writing, `meta.js` only exports middleware functions.
|
|
221
229
|
|
|
230
|
+
## Build-In Middleware
|
|
231
|
+
|
|
232
|
+
`sleepy-serv` also comes built-in with a few useful middleware functions that are commonly used.
|
|
233
|
+
|
|
234
|
+
### parseJson(req, _res)
|
|
235
|
+
|
|
236
|
+
This middleware parses the request's `body` property as a JSON string, and then stores the results in `res.body`. Additional body parsers can be written in the future a accommodate other body encoding schemes.
|
|
237
|
+
|
|
238
|
+
### validateSchema(schemas)
|
|
239
|
+
|
|
240
|
+
This function takes a `schemas` object. Each property is optional:
|
|
241
|
+
- `headers`: takes a string formatter schema to evaulate `req.headers`
|
|
242
|
+
- `params`: takes a string formatter schema to evaulate `req.params`
|
|
243
|
+
- `query`: takes a string foramtter schema to evaulate `req.query`
|
|
244
|
+
- `body`: takes a JSON validation schema to evaulate `res.body`
|
|
245
|
+
|
|
246
|
+
Here's an example of the schema in action:
|
|
247
|
+
|
|
248
|
+
```
|
|
249
|
+
PUT /contacts/123/addresses
|
|
250
|
+
|
|
251
|
+
{
|
|
252
|
+
street1: '123 Main St.',
|
|
253
|
+
street2: '#100',
|
|
254
|
+
city: 'Las Vegas',
|
|
255
|
+
state: 'NV',
|
|
256
|
+
postalCode: '12345',
|
|
257
|
+
}
|
|
258
|
+
```
|
|
259
|
+
|
|
260
|
+
***
|
|
261
|
+
TODO: add JSON schema example.
|
|
262
|
+
|
|
263
|
+
Please take a look at the `lib/src/middleware.test.js` test file for a far a comprehensive set of examples on how to use this middleware.
|
|
264
|
+
***
|
|
265
|
+
|
|
266
|
+
The `headers`, `params`, and `query` (querystrings) can only be strings, so they're evaulated using a simplified _string format schema_ instead of a full JSON schema.
|
|
267
|
+
|
|
268
|
+
The string formatter schema looks like this:
|
|
269
|
+
|
|
270
|
+
```javascript
|
|
271
|
+
{
|
|
272
|
+
type: 'format',
|
|
273
|
+
value: 'email',
|
|
274
|
+
}
|
|
275
|
+
```
|
|
276
|
+
|
|
277
|
+
**`type`**
|
|
278
|
+
|
|
279
|
+
Can either set to `'format'` or `'pattern'`. The value of `type` determines how the `value` property is used.
|
|
280
|
+
|
|
281
|
+
**`value`**
|
|
282
|
+
|
|
283
|
+
This determines how to evaulate the string based on the `type` parameter. If `type` is set to `'format'`, then `value` can be set to one of the pre-defined formats that's provided by the JSON schema specification. If `type` is set to `'pattern'`, then `value` can be set to a regex pattern instead.
|
|
284
|
+
|
|
285
|
+
Custom formats can also be provided by using the `setValidationFormats()` during app initialization. Here's an example:
|
|
286
|
+
|
|
287
|
+
```javascript
|
|
288
|
+
middleware.setValidationFormats({
|
|
289
|
+
phone: /^\d{10}$/, /* 10-digit, numeric string */
|
|
290
|
+
postalCode: /^\d{5}$/, /* 5-digit, numeric string */
|
|
291
|
+
})
|
|
292
|
+
```
|
|
293
|
+
|
|
294
|
+
Calling `setValidationFormats()` extends the possible values that can be passed to the `value` property when evaulating strings in either the string formatter schema, or the `res.body`'s JSON schema.
|
|
295
|
+
|
|
222
296
|
## `createApp()` Options
|
|
223
297
|
|
|
224
298
|
### `hostname`
|
package/package.json
CHANGED
package/src/index.js
CHANGED
|
@@ -45,17 +45,18 @@ function methodNotAllowedHandler (_req) {
|
|
|
45
45
|
throw new MethodNotAllowedError()
|
|
46
46
|
}
|
|
47
47
|
|
|
48
|
+
/* TODO: add whitelist support */
|
|
48
49
|
function validateDirectoryIllegalFiles (targetPath, filenames) {
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
Directory contains illegal files:
|
|
56
|
-
${targetPath}
|
|
57
|
-
|
|
58
|
-
|
|
50
|
+
// const hasInvalidFiles = filenames.some(filename =>
|
|
51
|
+
// !ALLOWED_FILES_ALL.includes(filename)
|
|
52
|
+
// )
|
|
53
|
+
|
|
54
|
+
// if (hasInvalidFiles) {
|
|
55
|
+
// throw new TypeError(`
|
|
56
|
+
// Directory contains illegal files:
|
|
57
|
+
// ${targetPath}
|
|
58
|
+
// `.trim())
|
|
59
|
+
// }
|
|
59
60
|
}
|
|
60
61
|
|
|
61
62
|
function validateLeafDirectory (targetPath, filenames, entries) {
|
|
@@ -187,14 +188,15 @@ ${route.modulePath}
|
|
|
187
188
|
|
|
188
189
|
const handler = async req => {
|
|
189
190
|
const query = req.url.split('?')[1]
|
|
191
|
+
const res = {}
|
|
190
192
|
|
|
191
193
|
req.query = query ? querystring.parse(query) : {}
|
|
192
194
|
|
|
193
195
|
for (const fn of middlewareChain) {
|
|
194
|
-
const
|
|
196
|
+
const response = await fn(req, res)
|
|
195
197
|
|
|
196
|
-
if (
|
|
197
|
-
return
|
|
198
|
+
if (response) {
|
|
199
|
+
return response
|
|
198
200
|
}
|
|
199
201
|
}
|
|
200
202
|
}
|
package/src/middleware.js
CHANGED
|
@@ -46,14 +46,14 @@ function buildFormatterSchema (schema) {
|
|
|
46
46
|
}
|
|
47
47
|
}
|
|
48
48
|
|
|
49
|
-
export async function parseJson (req) {
|
|
49
|
+
export async function parseJson (req, res) {
|
|
50
50
|
const contentType = req.headers.get('content-type')
|
|
51
51
|
|
|
52
52
|
if (req.method !== 'GET' && contentType !== 'application/json') {
|
|
53
53
|
throw new UnsupportedMediaTypeError('content-type')
|
|
54
54
|
}
|
|
55
55
|
|
|
56
|
-
|
|
56
|
+
res.body = await req.json()
|
|
57
57
|
}
|
|
58
58
|
|
|
59
59
|
export function setValidationFormats (formats) {
|
|
@@ -61,12 +61,12 @@ export function setValidationFormats (formats) {
|
|
|
61
61
|
}
|
|
62
62
|
|
|
63
63
|
export function validateSchema (schemas) {
|
|
64
|
-
return function (req) {
|
|
64
|
+
return function (req, res) {
|
|
65
65
|
const formattedSchemas = {
|
|
66
66
|
headers: buildFormatterSchema(schemas.headers),
|
|
67
67
|
params: buildFormatterSchema(schemas.params),
|
|
68
68
|
query: buildFormatterSchema(schemas.query),
|
|
69
|
-
|
|
69
|
+
body: schemas.body || SCHEMA_EMPTY,
|
|
70
70
|
}
|
|
71
71
|
|
|
72
72
|
const ajv = new Ajv({
|
|
@@ -83,7 +83,7 @@ export function validateSchema (schemas) {
|
|
|
83
83
|
const errors = Object
|
|
84
84
|
.entries(formattedSchemas)
|
|
85
85
|
.reduce((accum, [key, schema]) => {
|
|
86
|
-
const data = req[key]
|
|
86
|
+
const data = key === 'body' ? res[key] : req[key]
|
|
87
87
|
const valid = schema ? ajv.validate(schema, data) : true
|
|
88
88
|
|
|
89
89
|
return !valid
|