Description
Hi! This is just an issue to get your opinion on adding a new onBundle
callback as part of the options
object, similar to onDereference
. I'm willing to contribute this, if you're open to adding this feature. Here's some context on why we need it:
We use json-schema-ref-parser to parse and bundle OpenAPI and AsyncAPI files, heavily relying on overriding the resolvers to fetch external references from GitHub.
One issue with that is: if external $ref
contains $schema
and $id
- the bundle()
function keeps them, but the resulting OpenAPI document fails validation, due to unexpected additional properties. Here's a concrete minimal example:
schema.json
{
"$schema": "http://json-schema.org/draft-07/schema#",
"$id": "someId",
"type": "object",
"properties": {
"exampleProperty": {
"description": "Lorem ipsum and so on",
"type": "boolean"
}
}
}
api.yaml
openapi: "3.0.3"
info:
title: Example API
version: "1.0"
servers:
- url: https://localhost:3000/v1
paths:
/example:
get:
responses:
'200':
description: OK
content:
application/json:
schema:
$ref: 'schema.json'
script.ts
import fs from 'node:fs/promises';
import $RefParser from '@apidevtools/json-schema-ref-parser';
import swaggerParser from '@apidevtools/swagger-parser';
import yaml from 'yaml';
const body = await fs.readFile('api.yaml', 'utf8');
const content = yaml.parse(body);
const result = await $RefParser.bundle(content, { resolve: { external: true } });
await fs.writeFile('bundledApi.yaml', yaml.stringify(result));
await swaggerParser.validate(result);
bundledApi.yaml
openapi: 3.0.3
info:
title: Example API
version: "1.0"
servers:
- url: https://localhost:3000/v1
paths:
/example:
get:
responses:
"200":
description: OK
content:
application/json:
schema:
$schema: http://json-schema.org/draft-07/schema#
$id: someId
type: object
properties:
exampleProperty:
description: Lorem ipsum and so on
type: boolean
This fails validation with:
SyntaxError: Swagger schema validation failed.
#/paths/~1example/get/responses/200/content/application~1json/schema must NOT have additional properties
#/paths/~1example/get/responses/200/content/application~1json/schema must NOT have additional properties
#/paths/~1example/get/responses/200/content/application~1json/schema must have required property '$ref'
#/paths/~1example/get/responses/200/content/application~1json/schema must match exactly one schema in oneOf
#/paths/~1example/get/responses/200 must have required property '$ref'
#/paths/~1example/get/responses/200 must match exactly one schema in oneOf
Removing $schema
and $id
would make it pass the validation, however there doesn't seem to be an easy way of doing that. If we were calling dereference()
instead of bundle()
- the problem would be trivially solved with something like this:
const result = await $RefParser.dereference(content, {
resolve: { external: true },
dereference: {
onDereference: (path: string, value: JSONSchemaObject) => {
if ('$schema' in value) {
delete value.$schema;
}
},
},
});
Do you think adding the possibility to pass in an onBundle
callback would make sense here? Or can our problem be solved in some other way? Appreciate any feedback.