Skip to content
4 changes: 2 additions & 2 deletions src/ByteBard.AsyncAPI.Readers/AsyncApiJsonDocumentReader.cs
Original file line number Diff line number Diff line change
Expand Up @@ -280,7 +280,7 @@ private IAsyncApiSerializable ResolveExternalReference(AsyncApiDiagnostic diagno
}
else
{
stream = loader.Load(new Uri(reference.Reference.ExternalResource, UriKind.RelativeOrAbsolute));
stream = loader.Load(this.settings.BaseUri, new Uri(reference.Reference.ExternalResource, UriKind.RelativeOrAbsolute));
this.context.Workspace.RegisterComponent(reference.Reference.ExternalResource, stream);
}

Expand Down Expand Up @@ -310,7 +310,7 @@ private async Task<IAsyncApiSerializable> ResolveExternalReferenceAsync(AsyncApi
}
else
{
stream = await loader.LoadAsync(new Uri(reference.Reference.ExternalResource, UriKind.RelativeOrAbsolute));
stream = await loader.LoadAsync(this.settings.BaseUri, new Uri(reference.Reference.ExternalResource, UriKind.RelativeOrAbsolute));
this.context.Workspace.RegisterComponent(reference.Reference.ExternalResource, stream);
}

Expand Down
5 changes: 5 additions & 0 deletions src/ByteBard.AsyncAPI.Readers/AsyncApiReaderSettings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,11 @@ public ICollection<IBindingParser<IBinding>>
/// </summary>
public bool LeaveStreamOpen { get; set; }

/// <summary>
/// Uri where relative references should be resolved from when using the External Reference Loader.
/// </summary>
public Uri? BaseUri { get; set; }

/// <summary>
/// External reference reader implementation provided by users for reading external resources.
/// </summary>
Expand Down
4 changes: 2 additions & 2 deletions src/ByteBard.AsyncAPI.Readers/Interface/IStreamLoader.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ namespace ByteBard.AsyncAPI.Readers.Interface

public interface IStreamLoader
{
Task<Stream> LoadAsync(Uri uri);
Task<Stream> LoadAsync(Uri baseUri, Uri uri);

Stream Load(Uri uri);
Stream Load(Uri baseUri, Uri uri);
}
}
54 changes: 34 additions & 20 deletions src/ByteBard.AsyncAPI.Readers/Services/DefaultStreamLoader.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,40 +11,54 @@ internal class DefaultStreamLoader : IStreamLoader
{
private static readonly HttpClient HttpClient = new HttpClient();

public Stream Load(Uri uri)
public Stream Load(Uri baseUri, Uri uri)
{
try
{
switch (uri.Scheme)
if (uri.IsAbsoluteUri)
{
case "file":
return File.OpenRead(uri.AbsolutePath);
case "http":
case "https":
return HttpClient.GetStreamAsync(uri).GetAwaiter().GetResult();
default:
throw new ArgumentException("Unsupported scheme");
switch (uri.Scheme.ToLowerInvariant())
{
case "file":
return File.OpenRead(uri.LocalPath);
case "http":
case "https":
return HttpClient.GetStreamAsync(uri).GetAwaiter().GetResult();
default:
throw new ArgumentException("Unsupported scheme");
}
}
else
{
return File.OpenRead(new Uri(baseUri, uri).LocalPath);
}
}
catch (Exception ex)
{
throw new AsyncApiReaderException($"Something went wrong trying to fetch '{uri.OriginalString}. {ex.Message}'", ex);
throw new AsyncApiReaderException($"Something went wrong trying to fetch '{uri.OriginalString}'. {ex.Message}", ex);
}
}

public async Task<Stream> LoadAsync(Uri uri)
public async Task<Stream> LoadAsync(Uri baseUri, Uri uri)
{
try
{
switch (uri.Scheme)
if (uri.IsAbsoluteUri)
{
switch (uri.Scheme.ToLowerInvariant())
{
case "file":
return File.OpenRead(uri.LocalPath);
case "http":
case "https":
return await HttpClient.GetStreamAsync(uri);
default:
throw new ArgumentException("Unsupported scheme");
}
}
else
{
case "file":
return File.OpenRead(uri.AbsolutePath);
case "http":
case "https":
return await HttpClient.GetStreamAsync(uri);
default:
throw new ArgumentException("Unsupported scheme");
return File.OpenRead(new Uri(baseUri, uri).LocalPath);
}
}
catch (Exception ex)
Expand All @@ -53,4 +67,4 @@ public async Task<Stream> LoadAsync(Uri uri)
}
}
}
}
}
13 changes: 10 additions & 3 deletions src/ByteBard.AsyncAPI/Services/AsyncApiWalker.cs
Original file line number Diff line number Diff line change
Expand Up @@ -587,8 +587,15 @@ private void Walk(AsyncApiOperationReply reply)

this.visitor.Visit(reply);

this.Walk(reply.Address);
this.Walk(reply.Channel as IAsyncApiReferenceable);
if (reply.Address != null)
{
this.Walk(reply.Address);
}

if (reply.Channel != null)
{
this.Walk(reply.Channel as IAsyncApiReferenceable);
}

foreach (var message in reply.Messages)
{
Expand Down Expand Up @@ -1211,4 +1218,4 @@ public void Walk(IAsyncApiElement element)
}
}
}
}
}
12 changes: 6 additions & 6 deletions test/ByteBard.AsyncAPI.Tests/Models/AsyncApiReference_Should.cs
Original file line number Diff line number Diff line change
Expand Up @@ -525,7 +525,7 @@ public MockStringLoader(string input)

private readonly string input;

public Stream Load(Uri uri)
public Stream Load(Uri baseUri, Uri uri)
{
var stream = new MemoryStream();
var writer = new StreamWriter(stream);
Expand All @@ -535,9 +535,9 @@ public Stream Load(Uri uri)
return stream;
}

public Task<Stream> LoadAsync(Uri uri)
public Task<Stream> LoadAsync(Uri baseUri, Uri uri)
{
return Task.FromResult(this.Load(uri));
return Task.FromResult(this.Load(baseUri, uri));
}
}

Expand All @@ -564,7 +564,7 @@ public class MockJsonSchemaLoader : IStreamLoader
description: Light intensity measured in lumens.
""";

public Stream Load(Uri uri)
public Stream Load(Uri baseUri, Uri uri)
{
var stream = new MemoryStream();
var writer = new StreamWriter(stream);
Expand All @@ -581,9 +581,9 @@ public Stream Load(Uri uri)
return stream;
}

public Task<Stream> LoadAsync(Uri uri)
public Task<Stream> LoadAsync(Uri baseUri, Uri uri)
{
return Task.FromResult(this.Load(uri));
return Task.FromResult(this.Load(baseUri, uri));
}
}
}
Loading