swagger-parser
swagger-parser copied to clipboard
[BUG] nested references to external schema are not resolved properly in swagger parser v3.
I have defined schema in following structure.
├── schema
├── com
├── wf
├── test
├── schema_a.yaml
├── schema_b.yaml
schema_a.yaml:
openapi: 3.0.0
info:
title: SCHEMA A
version: 1.0.2
description: Links
x-package: com.workfusion.test
components:
schemas:
TypeFromB:
$ref: 'schema/com/wf/test/schema_b.yaml#/components/schemas/MyType'
UnrelatedType:
type: object
schema_b.yaml:
openapi: 3.0.0
info:
title: SCHEMA B
version: 1.0.2
description: Links
x-package: com.workfusion.test
components:
schemas:
MyType:
type: string
and I want to parse the below schema:
openapi: 3.0.0
info:
title: REF SCHEMA A
version: 1.0.1
components:
schemas:
in:
type: object
properties:
schema_a_ref:
$ref: 'schema/com/wf/test/schema_a.yaml#/components/schemas/TypeFromB'
parsing using
OpenAPIV3Parser parser = new OpenAPIV3Parser();
ParseOptions options = new ParseOptions();
options.setResolve(true);
return parser.readContents(yamlSchema, null, options, schemaDir.toAbsolutePath().toString());
and I got below error: Unable to load RELATIVE ref: schema\com\wf\test\schema\com\wf\test\schema_b.yaml
Hi everyone, it looks the issue inside next method: io.swagger.v3.parser.processors.ExternalRefProcessor#processRefToExternalSchema:
if (isAnExternalRefFormat(ref)) {
if (!ref.equals(RefFormat.URL)) {
String schemaFullRef = schema.get$ref();
String parent = (file.contains("/")) ? file.substring(0, file.lastIndexOf('/')) : "";
if (!parent.isEmpty() && !schemaFullRef.startsWith("/")) {
if (schemaFullRef.contains("#/")) {
String[] parts = schemaFullRef.split("#/");
String schemaFullRefFilePart = parts[0];
String schemaFullRefInternalRefPart = parts[1];
schemaFullRef = Paths.get(parent, schemaFullRefFilePart).normalize().toString() + "#/" + schemaFullRefInternalRefPart;
} else {
schemaFullRef = Paths.get(parent, schemaFullRef).normalize().toString();
}
}
schema.set$ref(processRefToExternalSchema(schemaFullRef, ref));
}
}
Problem is that schema.get$ref() return string with value: ./schema/com/wf/test/schema_b.yaml#/components/schemas/MyType
parent value will be : ./schema/com/wf/test/
schemaFullRefFilePart : ./schema/com/wf/test/schema_b.yaml
and root cause: Paths.get(parent, schemaFullRefFilePart).normalize().toString()
will return: schema\com\wf\test\schema\com\wf\test\schema_b.yaml
Looks like one check was missed here: if schemaFullRefFilePart contains parent path - use only schemaFullRefFilePart otherwise use Paths.get(parent, schemaFullRef).
Same issue here.
Same issue encountered here too; https://github.com/swagger-api/swagger-parser/blob/master/modules/swagger-parser-v3/src/main/java/io/swagger/v3/parser/processors/ExternalRefProcessor.java#L122-L143
For me RefFormat ref is calculated as RefFormat.URL, but there's no logic to process these types of references.
Wondering if the code should be something like the following so that schema.set$ref(processRefToExternalSchema(schemaFullRef, ref)) is called for all external references?
if (schema.get$ref() != null) {
RefFormat ref = computeRefFormat(schema.get$ref());
if (isAnExternalRefFormat(ref)) {
String schemaFullRef = schema.get$ref();
if (!ref.equals(RefFormat.URL)) {
String parent = (file.contains("/")) ? file.substring(0, file.lastIndexOf('/')) : "";
if (!parent.isEmpty() && !schemaFullRef.startsWith("/")) {
if (schemaFullRef.contains("#/")) {
String[] parts = schemaFullRef.split("#/");
String schemaFullRefFilePart = parts[0];
String schemaFullRefInternalRefPart = parts[1];
schemaFullRef = Paths.get(parent, schemaFullRefFilePart).normalize().toString() + "#/" + schemaFullRefInternalRefPart;
} else {
schemaFullRef = Paths.get(parent, schemaFullRef).normalize().toString();
}
}
}
schema.set$ref(processRefToExternalSchema(schemaFullRef, ref));
} else {
processRefToExternalSchema(file + schema.get$ref(), RefFormat.RELATIVE);
}
}
Any sign of this being fixed? Thanks!