-
-
Notifications
You must be signed in to change notification settings - Fork 1.3k
External ref to a schema fails if root property of referred schema is a property of JsonSchema #3341
Description
This may be an odd file structure, but I believe it is legal. The main yaml references a schema in a different file. If the top level element in that file is any property of JsonSchema, (e.g., title, maximum, parent, etc), then NSwag fails. I used Title in this example, and basically, instead of adding a schema "Title" to JsonSchema.ExtensionData, it tries to set JsonSchema.Title.
This may actually be an issue with NJsonSchema, but this is how it manifests in NSwag.
Version info
$ nswag version
NSwag NPM CLI
NSwag command line tool for .NET Core NetCore21, toolchain v13.10.7.0 (NJsonSchema v10.3.9.0 (Newtonsoft.Json v11.0.0.0))
Visit http://NSwag.org for more information.
NSwag bin directory: C:\Users\JFREDERIC\AppData\Roaming\npm\node_modules\nswag\bin\binaries\NetCore21
NSwag version: 13.10.7.0
NJsonSchema version: 10.3.9.0 (Newtonsoft.Json v11.0.0.0)Contents of test_main.yaml
openapi: '3.0.3'
info:
title: Testcase API
version: '1.0'
paths:
/endpoint:
post:
requestBody:
content:
application/json:
schema:
$ref: 'test_ext.yaml#/Title'
responses:
'200':
description: SuccessContents of test_ext.yaml
Title:
type: objectContents of nswag.json
{
"runtime": "NetCore21",
"defaultVariables": null,
"documentGenerator": {
"fromDocument": {
"json": "./test_main.yaml",
"output": null
}
}
}What happens when I nswag run
NSwag NPM CLI
NSwag command line tool for .NET Core NetCore21, toolchain v13.10.7.0 (NJsonSchema v10.3.9.0 (Newtonsoft.Json v11.0.0.0))
Visit http://NSwag.org for more information.
NSwag bin directory: C:\Users\JFREDERIC\AppData\Roaming\npm\node_modules\nswag\bin\binaries\NetCore21
Executing file 'nswag.json' with variables ''...
System.InvalidOperationException: Could not resolve the JSON path 'test_ext.yaml#/Title' within the file path '.\test_ext.yaml'. ---> Newtonsoft.Json.JsonReaderException: Unexpected character encountered while parsing value: {. Path 'Title', line 1, position 11.
at Newtonsoft.Json.JsonTextReader.ReadStringValue(ReadType readType)
at Newtonsoft.Json.JsonTextReader.ReadAsString()
at Newtonsoft.Json.JsonReader.ReadForType(JsonContract contract, Boolean hasConverter)
at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.PopulateObject(Object newObject, JsonReader reader, JsonObjectContract contract, JsonProperty member, String id)
at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.Populate(JsonReader reader, Object target)
at NJsonSchema.ExtensionDataDeserializationConverter.ReadJson(JsonReader reader, Type objectType, Object existingValue, JsonSerializer serializer)
at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.DeserializeConvertable(JsonConverter converter, JsonReader reader, Type objectType, Object existingValue)
at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.Deserialize(JsonReader reader, Type objectType, Boolean checkAdditionalContent)
at Newtonsoft.Json.JsonSerializer.DeserializeInternal(JsonReader reader, Type objectType)
at Newtonsoft.Json.JsonConvert.DeserializeObject(String value, Type type, JsonSerializerSettings settings)
at Newtonsoft.Json.JsonConvert.DeserializeObject[T](String value, JsonSerializerSettings settings)
at NJsonSchema.Infrastructure.JsonSchemaSerialization.FromJson[T](String json, IContractResolver contractResolver)
at NJsonSchema.Infrastructure.JsonSchemaSerialization.FromJsonAsync[T](String json, SchemaType schemaType, String documentPath, Func`2 referenceResolverFactory, IContractResolver contractResolver, CancellationToken cancellationToken)
at NJsonSchema.JsonSchema.FromJsonAsync(String data, String documentPath, Func`2 referenceResolverFactory, CancellationToken cancellationToken)
at NJsonSchema.Yaml.JsonSchemaYaml.FromYamlAsync(String data, String documentPath, Func`2 referenceResolverFactory, CancellationToken cancellationToken)
at NJsonSchema.Yaml.JsonSchemaYaml.FromFileAsync(String filePath, Func`2 referenceResolverFactory, CancellationToken cancellationToken)
at NJsonSchema.Yaml.JsonAndYamlReferenceResolver.ResolveFileReferenceAsync(String filePath, CancellationToken cancellationToken)
at NJsonSchema.JsonReferenceResolver.ResolveFileReferenceWithAlreadyResolvedCheckAsync(String filePath, Type targetType, IContractResolver contractResolver, String jsonPath, Boolean append, CancellationToken cancellationToken)
--- End of inner exception stack trace ---
at NJsonSchema.JsonReferenceResolver.ResolveFileReferenceWithAlreadyResolvedCheckAsync(String filePath, Type targetType, IContractResolver contractResolver, String jsonPath, Boolean append, CancellationToken cancellationToken)
at NJsonSchema.JsonReferenceResolver.ResolveReferenceAsync(Object rootObject, String jsonPath, Type targetType, IContractResolver contractResolver, Boolean append, CancellationToken cancellationToken)
at NJsonSchema.JsonReferenceResolver.ResolveReferenceAsync(Object rootObject, String jsonPath, Type targetType, IContractResolver contractResolver, CancellationToken cancellationToken)
at NJsonSchema.JsonSchemaReferenceUtilities.JsonReferenceUpdater.VisitJsonReferenceAsync(IJsonReference reference, String path, String typeNameHint, CancellationToken cancellationToken)
at NJsonSchema.Visitors.AsyncJsonReferenceVisitorBase.VisitAsync(Object obj, String path, String typeNameHint, ISet`1 checkedObjects, Action`1 replacer, CancellationToken cancellationToken)
at NJsonSchema.Visitors.AsyncJsonReferenceVisitorBase.VisitAsync(Object obj, String path, String typeNameHint, ISet`1 checkedObjects, Action`1 replacer, CancellationToken cancellationToken)
at NJsonSchema.Visitors.AsyncJsonReferenceVisitorBase.VisitAsync(Object obj, String path, String typeNameHint, ISet`1 checkedObjects, Action`1 replacer, CancellationToken cancellationToken)
at NJsonSchema.Visitors.AsyncJsonReferenceVisitorBase.VisitAsync(Object obj, String path, String typeNameHint, ISet`1 checkedObjects, Action`1 replacer, CancellationToken cancellationToken)
at NJsonSchema.Visitors.AsyncJsonReferenceVisitorBase.VisitAsync(Object obj, String path, String typeNameHint, ISet`1 checkedObjects, Action`1 replacer, CancellationToken cancellationToken)
at NJsonSchema.Visitors.AsyncJsonReferenceVisitorBase.VisitAsync(Object obj, String path, String typeNameHint, ISet`1 checkedObjects, Action`1 replacer, CancellationToken cancellationToken)
at NJsonSchema.Visitors.AsyncJsonReferenceVisitorBase.VisitAsync(Object obj, String path, String typeNameHint, ISet`1 checkedObjects, Action`1 replacer, CancellationToken cancellationToken)
at NJsonSchema.Visitors.AsyncJsonReferenceVisitorBase.VisitAsync(Object obj, CancellationToken cancellationToken)
at NJsonSchema.JsonSchemaReferenceUtilities.JsonReferenceUpdater.VisitAsync(Object obj, CancellationToken cancellationToken)
at NJsonSchema.JsonSchemaReferenceUtilities.UpdateSchemaReferencesAsync(Object rootObject, JsonReferenceResolver referenceResolver, IContractResolver contractResolver, CancellationToken cancellationToken)
at NJsonSchema.Infrastructure.JsonSchemaSerialization.FromJsonAsync[T](String json, SchemaType schemaType, String documentPath, Func`2 referenceResolverFactory, IContractResolver contractResolver, CancellationToken cancellationToken)
at NSwag.OpenApiDocument.FromJsonAsync(String data, String documentPath, SchemaType expectedSchemaType, Func`2 referenceResolverFactory, CancellationToken cancellationToken) in C:\projects\nswag\src\NSwag.Core\OpenApiDocument.cs:line 197
at NSwag.OpenApiYamlDocument.FromYamlAsync(String data, String documentPath, SchemaType expectedSchemaType, Func`2 referenceResolverFactory, CancellationToken cancellationToken) in C:\projects\nswag\src\NSwag.Core.Yaml\OpenApiYamlDocument.cs:line 76
at NSwag.OpenApiYamlDocument.FromFileAsync(String filePath, CancellationToken cancellationToken) in C:\projects\nswag\src\NSwag.Core.Yaml\OpenApiYamlDocument.cs:line 98
at NSwag.Commands.OutputCommandBase.ReadSwaggerDocumentAsync(String input) in C:\projects\nswag\src\NSwag.Commands\Commands\OutputCommandBase.cs:line 49
at NSwag.Commands.Generation.FromDocumentCommand.RunAsync() in C:\projects\nswag\src\NSwag.Commands\Commands\Generation\FromDocumentCommand.cs:line 62
at NSwag.Commands.Generation.FromDocumentCommand.RunAsync(CommandLineProcessor processor, IConsoleHost host) in C:\projects\nswag\src\NSwag.Commands\Commands\Generation\FromDocumentCommand.cs:line 53
at NSwag.Commands.NSwagDocumentBase.GenerateSwaggerDocumentAsync() in C:\projects\nswag\src\NSwag.Commands\NSwagDocumentBase.cs:line 280
at NSwag.Commands.NSwagDocument.ExecuteAsync() in C:\projects\nswag\src\NSwag.Commands\NSwagDocument.cs:line 81
at NSwag.Commands.Document.ExecuteDocumentCommand.ExecuteDocumentAsync(IConsoleHost host, String filePath) in C:\projects\nswag\src\NSwag.Commands\Commands\Document\ExecuteDocumentCommand.cs:line 85
at NSwag.Commands.Document.ExecuteDocumentCommand.RunAsync(CommandLineProcessor processor, IConsoleHost host) in C:\projects\nswag\src\NSwag.Commands\Commands\Document\ExecuteDocumentCommand.cs:line 39
at NConsole.CommandLineProcessor.ProcessSingleAsync(String[] args, Object input)
at NConsole.CommandLineProcessor.ProcessAsync(String[] args, Object input)
at NConsole.CommandLineProcessor.Process(String[] args, Object input)
at NSwag.Commands.NSwagCommandProcessor.Process(String[] args) in C:\projects\nswag\src\NSwag.Commands\NSwagCommandProcessor.cs:line 56child_process.js:655
throw err;
^
Error: Command failed: dotnet "C:\Users\JFREDERIC\AppData\Roaming\npm\node_modules\nswag\bin/binaries/NetCore21/dotnet-nswag.dll" run
at checkExecSyncError (child_process.js:616:11)
at Object.execSync (child_process.js:652:15)
at C:\Users\JFREDERIC\AppData\Roaming\npm\node_modules\nswag\bin\nswag.js:67:11
at ChildProcess.exithandler (child_process.js:299:7)
at ChildProcess.emit (events.js:315:20)
at maybeClose (internal/child_process.js:1048:16)
at Socket.<anonymous> (internal/child_process.js:439:11)
at Socket.emit (events.js:315:20)
at Pipe.<anonymous> (net.js:673:12) {
status: 4294967295,
signal: null,
output: [ null, null, null ],
pid: 45272,
stdout: null,
stderr: null
}This problem is easy enough to work around by modifying the OpenAPI document, when you control those files. One fix to the example OpenApi doc files used here is simply to nest the references one level deeper. E.g.:
Contents of test_main.yaml, "fixed"
openapi: '3.0.3'
info:
title: Testcase API
version: '1.0'
paths:
/endpoint:
post:
requestBody:
content:
application/json:
schema:
$ref: 'test_ext.yaml#/nestDeeperAsWorkaround/Title'
responses:
'200':
description: SuccessContents of test_ext.yaml, "fixed"
nestDeeperAsWorkaround:
Title:
type: object