mirror of
https://github.com/djdevin/recflare.git
synced 2026-09-08 22:51:30 -07:00
add some basic validation
This commit is contained in:
@@ -33,9 +33,44 @@ function addIntegerExamples(node: unknown): void {
|
||||
for (const value of Object.values(obj)) addIntegerExamples(value)
|
||||
}
|
||||
|
||||
/**
|
||||
* hono-openapi registers a `validator('form', …)` body under `multipart/form-data` ONLY,
|
||||
* and there is no way to ask it for another media type: its media selection reads
|
||||
* `options?.media ?? target === 'json' ? 'application/json' : 'multipart/form-data'`,
|
||||
* which by JS precedence is `((options?.media ?? target) === 'json') ? … : …` — so the
|
||||
* `media` option can never produce anything else.
|
||||
*
|
||||
* That leaves the spec claiming a validated route accepts only multipart, when the real
|
||||
* callers (the Rec Room client and the website) post `application/x-www-form-urlencoded`
|
||||
* and Hono's `parseBody()` reads both. So the urlencoded variant is mirrored back in.
|
||||
*
|
||||
* Safe because nothing here documents a genuinely multipart-only body — there are no file
|
||||
* uploads on these workers, and hand-written form bodies already declare both types. If
|
||||
* one is ever added, it will need to opt out of this.
|
||||
*/
|
||||
function mirrorFormBodies(node: unknown): void {
|
||||
if (Array.isArray(node)) {
|
||||
for (const item of node) mirrorFormBodies(item)
|
||||
return
|
||||
}
|
||||
if (node === null || typeof node !== 'object') return
|
||||
|
||||
const obj = node as Record<string, unknown>
|
||||
const content = obj.content
|
||||
if (content !== null && typeof content === 'object') {
|
||||
const media = content as Record<string, unknown>
|
||||
const multipart = media['multipart/form-data']
|
||||
if (multipart !== undefined && media['application/x-www-form-urlencoded'] === undefined) {
|
||||
media['application/x-www-form-urlencoded'] = multipart
|
||||
}
|
||||
}
|
||||
for (const value of Object.values(obj)) mirrorFormBodies(value)
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrap `openAPIRouteHandler(...)` so the generated document gets example values for its
|
||||
* integer fields. Purely cosmetic — nothing about the documented shapes changes.
|
||||
* integer fields, and so a validated form body documents both content types it really
|
||||
* accepts. Nothing about the runtime behaviour changes — this only corrects the document.
|
||||
*
|
||||
* ```ts
|
||||
* app.get('/openapi.json', describeRoute({ hide: true }), withCleanSpec(openAPIRouteHandler(app, { ... })))
|
||||
@@ -47,6 +82,7 @@ export function withCleanSpec(handler: Handler | MiddlewareHandler): Handler {
|
||||
if (!(res instanceof Response)) return res as never
|
||||
const spec: unknown = await res.json()
|
||||
addIntegerExamples(spec)
|
||||
mirrorFormBodies(spec)
|
||||
return c.json(spec as Record<string, unknown>)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user