Skip to content

Commit ed63267

Browse files
bieluclaude
andcommitted
fix: read multi-format payload fallbacks in 2.x documents
ResolveStreamReference is also the fallback for local references that are not in the workspace, not only for external ones. In a 2.x document every local payload reference is an AsyncApiMultiFormatSchemaReference, so the fallback asked the 2.x reader for an AsyncApiMultiFormatSchema loader it did not have and Read() threw KeyNotFoundException. The 2.x reader now loads a Multi Format Schema by reading the payload as a JSON Schema and wrapping it, since 2.x keeps schemaFormat on the message. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
1 parent 87a19e9 commit ed63267

3 files changed

Lines changed: 58 additions & 0 deletions

File tree

‎src/ByteBard.AsyncAPI.Readers/V2/AsyncApiMessageDeserializer.cs‎

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,14 @@ public static IAsyncApiSchema LoadAvroPayload(ParseNode n)
7373
return LoadPayload(n, "application/vnd.apache.avro");
7474
}
7575

76+
/// <summary>
77+
/// 2.x has no Multi Format Schema Object; the schema format lives on the message, so a payload read on its own is a JSON Schema.
78+
/// </summary>
79+
public static AsyncApiMultiFormatSchema LoadMultiFormatSchemaPayload(ParseNode n)
80+
{
81+
return new AsyncApiMultiFormatSchema { Schema = LoadJsonSchemaPayload(n) };
82+
}
83+
7684
private static IAsyncApiSchema LoadPayload(ParseNode n, string format)
7785
{
7886
if (n == null)

‎src/ByteBard.AsyncAPI.Readers/V2/AsyncApiV2VersionService.cs‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ public AsyncApiV2VersionService(AsyncApiDiagnostic diagnostic)
3636
[typeof(AsyncApiAvroSchema)] = AsyncApiAvroSchemaDeserializer.LoadSchema,
3737
[typeof(AsyncApiJsonSchema)] = AsyncApiV2Deserializer.LoadJsonSchemaPayload,
3838
[typeof(AsyncApiAvroSchema)] = AsyncApiV2Deserializer.LoadAvroPayload,
39+
[typeof(AsyncApiMultiFormatSchema)] = AsyncApiV2Deserializer.LoadMultiFormatSchemaPayload,
3940
[typeof(AsyncApiSecurityScheme)] = AsyncApiV2Deserializer.LoadSecurityScheme,
4041
[typeof(AsyncApiServer)] = AsyncApiV2Deserializer.LoadServer,
4142
[typeof(AsyncApiServerVariable)] = AsyncApiV2Deserializer.LoadServerVariable,

‎test/ByteBard.AsyncAPI.Tests/Models/AsyncApiReference_Should.cs‎

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -214,6 +214,55 @@ public void V3_ExternalPayloadReference_WithoutFragment_ResolvesPayload()
214214
doc.Channels["workspace"].Messages["message"].Payload.Schema.As<AsyncApiJsonSchema>().Type.Should().Be(SchemaType.Boolean);
215215
}
216216

217+
// A local payload reference that is not a registered component is resolved by falling back to the whole document.
218+
[TestCase("2.6.0")]
219+
[TestCase("3.0.0")]
220+
public void LocalPayloadReference_NotInWorkspace_ResolvesPayload(string version)
221+
{
222+
var yaml = version.StartsWith("2")
223+
? """
224+
asyncapi: 2.6.0
225+
info:
226+
title: test
227+
version: 1.0.0
228+
channels:
229+
workspace:
230+
publish:
231+
message:
232+
payload:
233+
$ref: '#/components/messages/shared/payload'
234+
components:
235+
messages:
236+
shared:
237+
payload:
238+
type: string
239+
"""
240+
: """
241+
asyncapi: 3.0.0
242+
info:
243+
title: test
244+
version: 1.0.0
245+
channels:
246+
workspace:
247+
messages:
248+
message:
249+
payload:
250+
$ref: '#/components/messages/shared/payload'
251+
components:
252+
messages:
253+
shared:
254+
payload:
255+
type: string
256+
""";
257+
258+
var doc = new AsyncApiStringReader().Read(yaml, out var diagnostic);
259+
260+
diagnostic.Errors.Should().BeEmpty();
261+
var payload = doc.Channels["workspace"].Messages.Values.First().Payload;
262+
payload.Should().BeOfType<AsyncApiMultiFormatSchemaReference>();
263+
payload.Schema.As<AsyncApiJsonSchema>().Type.Should().Be(SchemaType.String);
264+
}
265+
217266
[Test]
218267
public void V2_ReferencePointers()
219268
{

0 commit comments

Comments
 (0)