Skip to content

Commit 37032b6

Browse files
bieluclaude
andcommitted
fix: resolve external 3.x payload references
In 3.x a message payload reference is an AsyncApiMultiFormatSchemaReference. Resolving an external reference only handled JSON and Avro schema references, so an external payload such as `$ref: './payload.json'` was never read and reported "Unable to deserialize reference". The external content is now read as a Multi Format Schema Object, which also accepts a plain Schema Object. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
1 parent 7eed22a commit 37032b6

2 files changed

Lines changed: 81 additions & 0 deletions

File tree

‎src/ByteBard.AsyncAPI.Readers/AsyncApiJsonDocumentReader.cs‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -399,6 +399,11 @@ private IAsyncApiSerializable ResolveStreamReference(Stream stream, IAsyncApiRef
399399
result = this.ReadFragment<AsyncApiAvroSchema>(json, diagnostic.SpecificationVersion, out fragmentDiagnostic);
400400
}
401401

402+
if (reference is AsyncApiMultiFormatSchemaReference)
403+
{
404+
result = this.ReadFragment<AsyncApiMultiFormatSchema>(json, diagnostic.SpecificationVersion, out fragmentDiagnostic);
405+
}
406+
402407
break;
403408

404409
case ReferenceType.Server:

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

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,82 @@ namespace ByteBard.AsyncAPI.Tests
1414

1515
public class AsyncApiReference_Should : TestBase
1616
{
17+
private const string ExternalPayloads =
18+
"""
19+
{
20+
"schemas": {
21+
"plain": { "type": "string" },
22+
"multiFormat": {
23+
"schemaFormat": "application/vnd.aai.asyncapi+json;version=3.0.0",
24+
"schema": { "type": "integer" }
25+
}
26+
}
27+
}
28+
""";
29+
30+
[TestCase("payloads.json#/schemas/plain", SchemaType.String)]
31+
[TestCase("payloads.json#/schemas/multiFormat", SchemaType.Integer)]
32+
public void V3_ExternalPayloadReference_ResolvesPayload(string reference, SchemaType expectedType)
33+
{
34+
var yaml =
35+
$"""
36+
asyncapi: 3.0.0
37+
info:
38+
title: test
39+
version: 1.0.0
40+
channels:
41+
workspace:
42+
messages:
43+
message:
44+
payload:
45+
$ref: '{reference}'
46+
""";
47+
48+
var settings = new AsyncApiReaderSettings
49+
{
50+
ReferenceResolution = ReferenceResolutionSetting.ResolveAllReferences,
51+
ExternalReferenceLoader = new MockStringLoader(ExternalPayloads),
52+
};
53+
54+
var doc = new AsyncApiStringReader(settings).Read(yaml, out var diagnostic);
55+
56+
diagnostic.Errors.Should().BeEmpty();
57+
var payload = doc.Channels["workspace"].Messages["message"].Payload;
58+
payload.Should().BeOfType<AsyncApiMultiFormatSchemaReference>();
59+
payload.As<AsyncApiMultiFormatSchemaReference>().UnresolvedReference.Should().BeFalse();
60+
payload.Schema.As<AsyncApiJsonSchema>().Type.Should().Be(expectedType);
61+
doc.SerializeAsYaml(AsyncApiVersion.AsyncApi3_0).Should().Contain($"$ref: {reference}");
62+
}
63+
64+
[Test]
65+
public void V3_ExternalPayloadReference_WithoutFragment_ResolvesPayload()
66+
{
67+
var yaml =
68+
"""
69+
asyncapi: 3.0.0
70+
info:
71+
title: test
72+
version: 1.0.0
73+
channels:
74+
workspace:
75+
messages:
76+
message:
77+
payload:
78+
$ref: './payload.json'
79+
""";
80+
81+
var settings = new AsyncApiReaderSettings
82+
{
83+
ReferenceResolution = ReferenceResolutionSetting.ResolveAllReferences,
84+
ExternalReferenceLoader = new MockStringLoader("""{ "type": "boolean" }"""),
85+
};
86+
87+
var doc = new AsyncApiStringReader(settings).Read(yaml, out var diagnostic);
88+
89+
diagnostic.Errors.Should().BeEmpty();
90+
doc.Channels["workspace"].Messages["message"].Payload.Schema.As<AsyncApiJsonSchema>().Type.Should().Be(SchemaType.Boolean);
91+
}
92+
1793
[Test]
1894
public void V2_ReferencePointers()
1995
{

0 commit comments

Comments
 (0)