Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(references)!: add basic scaffolding for external ref resolution #168

Merged
merged 40 commits into from
May 15, 2024
Merged
Show file tree
Hide file tree
Changes from 35 commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
4f1edc3
chore: update CHANGELOG.md
lego-10-01-06[bot] Dec 14, 2023
c336ed8
Update README.md
VisualBean Jan 12, 2024
4a6c6a8
feat: added new topic configuration properties
gokerakc Feb 12, 2024
eace86d
fix: updated topic configuration data types
gokerakc Feb 14, 2024
1e463fc
chore: update CHANGELOG.md
lego-10-01-06[bot] Feb 15, 2024
0d516ce
ci: add run number to beta releases.
VisualBean Feb 15, 2024
93ba475
fix: long values for missing retention properties
VisualBean Feb 16, 2024
b58f042
chore: update CHANGELOG.md
lego-10-01-06[bot] Feb 16, 2024
9063f4e
feat: improve AsyncApiAny api surface.
VisualBean Feb 26, 2024
72588e7
ci: run test for test changes
VisualBean Feb 29, 2024
9291da6
feat: targetframework to netstandard2.0 (#150)
ByronMayne Mar 14, 2024
8d128db
feat(bindings): add amqp bindings (#153)
VisualBean Mar 25, 2024
f5529e0
feat(bindings): add mqtt bindings (#154)
VisualBean Mar 26, 2024
581f680
chore: add TryGetValue extensions for bindings (#156)
VisualBean Mar 26, 2024
ee91a56
refactor: remove unused expressions (#155)
VisualBean Mar 26, 2024
18f2cb3
test: remove stylecop from tests (#158)
VisualBean Mar 26, 2024
6169554
chore: fix warnings (#157)
VisualBean Mar 26, 2024
efcf8f0
chore: add net 6 as TFM to make STJ conditional (#163)
thompson-tomo Mar 30, 2024
0199420
feat: add cultureinfo to reader/writer settings. (#152)
ByronMayne Mar 30, 2024
f3bff4a
chore: null check for Serialize<T> (#165)
VisualBean Mar 30, 2024
5cd3a6b
test: use raw strings (#164)
VisualBean Mar 30, 2024
cf6cf6d
chore: update CHANGELOG.md
lego-10-01-06[bot] Mar 30, 2024
8908ace
feat: add basic scaffolding
Apr 19, 2024
fe2c81b
feat: Add tests
Apr 19, 2024
bd23300
feat: use external reference resolver
Apr 25, 2024
32364f7
feat: basic external reading working
Apr 29, 2024
998a88a
feat: Add testing for recursive references
Apr 29, 2024
7ada695
feat: add docs
Apr 30, 2024
b2b5956
feat: revert comment
Apr 30, 2024
48ad9c1
feat: remove line
Apr 30, 2024
697f45b
feat: add doc strings for interface
Apr 30, 2024
8c19ef1
feat: more clean up
May 1, 2024
bdc7b9c
feat: move interface and delete reference error
May 1, 2024
69f3c21
feat: add error handling for unconfigured reader
May 1, 2024
c6ea236
feat: clean up and testing
May 1, 2024
b297e1b
feat: revert to ResolveReferences
May 3, 2024
08a4288
feat: clean up reference resolution
May 7, 2024
90c25e6
feat: update docs
May 7, 2024
c2f6a16
feat: address DoNotResolve branches
May 8, 2024
17c0183
feat: merge diagnostic errors from fragment reads
May 9, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,13 @@ on:
branches: [ main, vnext ]
paths:
- 'src/**'
- 'test/**'
- '!**/*.md'
pull_request:
branches: [ main, vnext ]
paths:
- 'src/**'
- 'test/**'
- '!**/*.md'
workflow_dispatch:
jobs:
Expand All @@ -23,7 +25,7 @@ jobs:
- name: Setup .NET
uses: actions/setup-dotnet@v1
with:
dotnet-version: '6.0.x'
dotnet-version: '8.0.x'
include-prerelease: true
- name: Restore dependencies
run: dotnet restore
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/release-internal.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
name: Publish internal NuGet package
name: Publish beta NuGet package
on:
push:
branches: [ main ]
Expand Down Expand Up @@ -46,7 +46,7 @@ jobs:
uses: actions/setup-dotnet@v1

- name: Build ${{ matrix.package-name }} project and pack NuGet package
run: dotnet pack src/${{ matrix.package-name }}/${{ matrix.package-name }}.csproj -c Release -o out-${{ matrix.package-name }} -p:PackageVersion=${{ needs.check.outputs.version }}-beta
run: dotnet pack src/${{ matrix.package-name }}/${{ matrix.package-name }}.csproj -c Release -o out-${{ matrix.package-name }} -p:PackageVersion=${{ needs.check.outputs.version }}-beta.${{github.run_number}}

- name: Push generated package to GitHub Packages registry
run: dotnet nuget push out-${{ matrix.package-name }}/*.nupkg -s https://api.nuget.org/v3/index.json --skip-duplicate -n --api-key ${{secrets.NUGET}}
3 changes: 2 additions & 1 deletion AsyncAPI.sln
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,10 @@ EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{DE167614-5BCB-4046-BD4C-ABB70E9F3462}"
ProjectSection(SolutionItems) = preProject
.editorconfig = .editorconfig
Common.Build.props = Common.Build.props
EndProjectSection
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LEGO.AsyncAPI.Bindings", "src\LEGO.AsyncAPI.Bindings\LEGO.AsyncAPI.Bindings.csproj", "{33CA31F4-ECFE-4227-BFE9-F49783DD29A0}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LEGO.AsyncAPI.Bindings", "src\LEGO.AsyncAPI.Bindings\LEGO.AsyncAPI.Bindings.csproj", "{33CA31F4-ECFE-4227-BFE9-F49783DD29A0}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Expand Down
53 changes: 53 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,56 @@
# [5.2.0](https://github.com/LEGO/AsyncAPI.NET/compare/v5.1.1...v5.2.0) (2024-03-30)


### Features

* add cultureinfo to reader/writer settings. ([#152](https://github.com/LEGO/AsyncAPI.NET/issues/152)) ([0199420](https://github.com/LEGO/AsyncAPI.NET/commit/01994205ecde4e17317762374b03ec23aad17022))
* **bindings:** add amqp bindings ([#153](https://github.com/LEGO/AsyncAPI.NET/issues/153)) ([8d128db](https://github.com/LEGO/AsyncAPI.NET/commit/8d128db869d8164cfaad156d4f29a7130a00827e))
* **bindings:** add mqtt bindings ([#154](https://github.com/LEGO/AsyncAPI.NET/issues/154)) ([f5529e0](https://github.com/LEGO/AsyncAPI.NET/commit/f5529e0e96d139e0cb1958d6b0620ed826e21cb5))
* improve AsyncApiAny api surface. ([9063f4e](https://github.com/LEGO/AsyncAPI.NET/commit/9063f4e4f19929f8ccbdee5bd46dd9e27a3e0c08))
* targetframework to netstandard2.0 ([#150](https://github.com/LEGO/AsyncAPI.NET/issues/150)) ([9291da6](https://github.com/LEGO/AsyncAPI.NET/commit/9291da603335fd202b59f421945629952f136296))

## [5.1.1](https://github.com/LEGO/AsyncAPI.NET/compare/v5.1.0...v5.1.1) (2024-02-16)


### Bug Fixes

* long values for missing retention properties ([93ba475](https://github.com/LEGO/AsyncAPI.NET/commit/93ba4755babd05a0d21f3530aab417eeed3b7073))

# [5.1.0](https://github.com/LEGO/AsyncAPI.NET/compare/v5.0.0...v5.1.0) (2024-02-15)


### Bug Fixes

* updated topic configuration data types ([eace86d](https://github.com/LEGO/AsyncAPI.NET/commit/eace86dde4fc704d4652d19e7073be3b37ade6c7))


### Features

* added new topic configuration properties ([4a6c6a8](https://github.com/LEGO/AsyncAPI.NET/commit/4a6c6a8fed3a970153bd511daad5e614dbcdf2df))

# [5.0.0](https://github.com/LEGO/AsyncAPI.NET/compare/v4.1.0...v5.0.0) (2023-12-14)


### Bug Fixes

* add type to references, always. ([#139](https://github.com/LEGO/AsyncAPI.NET/issues/139)) ([3031023](https://github.com/LEGO/AsyncAPI.NET/commit/30310232bb3869258486d9f7f85721d4e3fb46eb))
* added missing mapping for ordering ([#138](https://github.com/LEGO/AsyncAPI.NET/issues/138)) ([510426e](https://github.com/LEGO/AsyncAPI.NET/commit/510426e200b4fe97ad1b8e9a6e94a615593c2a3c))
* patternProperties should also be walked as a reference ([#133](https://github.com/LEGO/AsyncAPI.NET/issues/133)) ([dc544f1](https://github.com/LEGO/AsyncAPI.NET/commit/dc544f1c01be3b95ded08ee894453ce8529eafb3))


* chore(settings)!: make reader bindings IEnumerable to allow for simpler usage ([e1f8c87](https://github.com/LEGO/AsyncAPI.NET/commit/e1f8c8766767ce642546a911810064a5234f04c3))


### Features

* allow non-component references ([#132](https://github.com/LEGO/AsyncAPI.NET/issues/132)) ([71fe571](https://github.com/LEGO/AsyncAPI.NET/commit/71fe571a3db0b4fbc13f4573b4d4b53f4f6b0911))
* **bindings:** add high throughput fifo properties ([#135](https://github.com/LEGO/AsyncAPI.NET/issues/135)) ([44ffcf4](https://github.com/LEGO/AsyncAPI.NET/commit/44ffcf4ceaf06a5168597e1eeb9407f09d47ab23))


### BREAKING CHANGES

* changes how bindings are applied.

# [4.1.0](https://github.com/LEGO/AsyncAPI.NET/compare/v4.0.2...v4.1.0) (2023-09-27)


Expand Down
13 changes: 13 additions & 0 deletions Common.Build.props
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<Project>
<!-- Common Properties used by all assemblies -->
<PropertyGroup>
<LangVersion>10</LangVersion>
<TargetFrameworks>netstandard2.0;net6</TargetFrameworks>
<ImplicitUsings>disable</ImplicitUsings>
<Company>The LEGO Group</Company>
<PackageProjectUrl>https://github.com/LEGO/AsyncAPI.NET</PackageProjectUrl>
<PackageReadmeFile>README.md</PackageReadmeFile>
<RepositoryUrl>https://github.com/LEGO/AsyncAPI.NET</RepositoryUrl>
<PackageTags>asyncapi .net openapi documentation</PackageTags>
</PropertyGroup>
</Project>
41 changes: 40 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -78,13 +78,52 @@ var stream = await httpClient.GetStreamAsync("master/examples/streetlights-kafka
var asyncApiDocument = new AsyncApiStreamReader().Read(stream, out var diagnostic);
```

#### Reading External $ref

You can read externally referenced AsyncAPI documents by providing an implementation for the `IAsyncApiExternalReferenceReader` interface. This interface contains a single method that is passed the content of the `$ref` and returns a `string` which is the content retrieved from wherever the `$ref` points to. This interface allows users to load the content of their external reference however and from whereever is required. A new instance of the implementor of `IAsyncApiExternalReferenceReader` should be registered with the `ExternalReferenceReader` property of the `AsyncApiReaderSettings` when creating the reader from which the `GetExternalResource` method will be called when resolving external references.

Below is a very simple example of implementation for `IAsyncApiExternalReferenceReader` that simply loads a file and returns it as a string found at the reference endpoint.
```csharp
using System.IO;

public class AsyncApiExternalFileSystemReader : IAsyncApiExternalReferenceReader
{
public string GetExternalResource(string reference)
{
return File.ReadAllText(reference);
}
}
```

This can then be configured in the reader as follows:
```csharp
var settings = new AsyncApiReaderSettings
{
ExternalReferenceReader = new AsyncApiExternalFileSystemReader(),
};
var reader = new AsyncApiStringReader(settings);
```

This would function for a AsyncAPI document with following reference:
```yaml
asyncapi: 2.3.0
info:
title: test
version: 1.0.0
channels:
workspace:
publish:
message:
$ref: "../../../message.yaml"
```

### Bindings
To add support for reading bindings, simply add the bindings you wish to support, to the `Bindings` collection of `AsyncApiReaderSettings`.
There is a nifty helper to add different types of bindings, or like in the example `All` of them.

```csharp
var settings = new AsyncApiReaderSettings();
settings.Bindings.Add(BindingsCollection.All);
settings.Bindings = BindingsCollection.All;
var asyncApiDocument = new AsyncApiStringReader(settings).Read(stream, out var diagnostic);
```

Expand Down
86 changes: 86 additions & 0 deletions src/LEGO.AsyncAPI.Bindings/AMQP/AMQPChannelBinding.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
// Copyright (c) The LEGO Group. All rights reserved.

namespace LEGO.AsyncAPI.Bindings.AMQP
{
using System;
using LEGO.AsyncAPI.Models;
using LEGO.AsyncAPI.Readers.ParseNodes;
using LEGO.AsyncAPI.Writers;

/// <summary>
/// Binding class for AMQP channel settings.
/// </summary>
public class AMQPChannelBinding : ChannelBinding<AMQPChannelBinding>
{
/// <summary>
/// Defines what type of channel is it. Can be either queue or routingKey.
/// </summary>
public ChannelType Is { get; set; }

/// <summary>
/// When is=routingKey, this object defines the exchange properties.
/// </summary>
public Exchange Exchange { get; set; }

/// <summary>
/// When is=queue, this object defines the queue properties.
/// </summary>
public Queue Queue { get; set; }

public override string BindingKey => "amqp";

protected override FixedFieldMap<AMQPChannelBinding> FixedFieldMap => new()
{
{ "bindingVersion", (a, n) => { a.BindingVersion = n.GetScalarValue(); } },
{ "is", (a, n) => { a.Is = n.GetScalarValue().GetEnumFromDisplayName<ChannelType>(); } },
{ "exchange", (a, n) => { a.Exchange = n.ParseMap(ExchangeFixedFields); } },
{ "queue", (a, n) => { a.Queue = n.ParseMap(QueueFixedFields); } },
};

private static FixedFieldMap<Exchange> ExchangeFixedFields = new()
{
{ "name", (a, n) => { a.Name = n.GetScalarValue(); } },
{ "durable", (a, n) => { a.Durable = n.GetBooleanValue(); } },
{ "type", (a, n) => { a.Type = n.GetScalarValue().GetEnumFromDisplayName<ExchangeType>(); } },
{ "autoDelete", (a, n) => { a.AutoDelete = n.GetBooleanValue(); } },
{ "vhost", (a, n) => { a.Vhost = n.GetScalarValue(); } },
};

private static FixedFieldMap<Queue> QueueFixedFields = new()
{
{ "name", (a, n) => { a.Name = n.GetScalarValue(); } },
{ "durable", (a, n) => { a.Durable = n.GetBooleanValue(); } },
{ "exclusive", (a, n) => { a.Exclusive = n.GetBooleanValue(); } },
{ "autoDelete", (a, n) => { a.AutoDelete = n.GetBooleanValue(); } },
{ "vhost", (a, n) => { a.Vhost = n.GetScalarValue(); } },
};

/// <summary>
/// Serialize to AsyncAPI V2 document without using reference.
/// </summary>
public override void SerializeProperties(IAsyncApiWriter writer)
{
if (writer is null)
{
throw new ArgumentNullException(nameof(writer));
}

writer.WriteStartObject();
writer.WriteRequiredProperty("is", this.Is.GetDisplayName());
switch (this.Is)
{
case ChannelType.RoutingKey:
writer.WriteOptionalObject("exchange", this.Exchange, (w, t) => t.Serialize(w));
break;
case ChannelType.Queue:
writer.WriteOptionalObject("queue", this.Queue, (w, t) => t.Serialize(w));
break;
}

writer.WriteOptionalProperty(AsyncApiConstants.BindingVersion, this.BindingVersion);
writer.WriteExtensions(this.Extensions);

writer.WriteEndObject();
}
}
}
51 changes: 51 additions & 0 deletions src/LEGO.AsyncAPI.Bindings/AMQP/AMQPMessageBinding.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
// Copyright (c) The LEGO Group. All rights reserved.

namespace LEGO.AsyncAPI.Bindings.AMQP
{
using System;
using LEGO.AsyncAPI.Models;
using LEGO.AsyncAPI.Readers.ParseNodes;
using LEGO.AsyncAPI.Writers;

/// <summary>
/// Binding class for AMQP messages.
/// </summary>
public class AMQPMessageBinding : MessageBinding<AMQPMessageBinding>
{
/// <summary>
/// A MIME encoding for the message content.
/// </summary>
public string ContentEncoding { get; set; }

/// <summary>
/// Application-specific message type.
/// </summary>
public string MessageType { get; set; }

public override void SerializeProperties(IAsyncApiWriter writer)
{
if (writer is null)
{
throw new ArgumentNullException(nameof(writer));
}

writer.WriteStartObject();

writer.WriteOptionalProperty("contentEncoding", this.ContentEncoding);
writer.WriteOptionalProperty("messageType", this.MessageType);
writer.WriteOptionalProperty(AsyncApiConstants.BindingVersion, this.BindingVersion);
writer.WriteExtensions(this.Extensions);

writer.WriteEndObject();
}

public override string BindingKey => "amqp";

protected override FixedFieldMap<AMQPMessageBinding> FixedFieldMap => new()
{
{ "bindingVersion", (a, n) => { a.BindingVersion = n.GetScalarValue(); } },
{ "contentEncoding", (a, n) => { a.ContentEncoding = n.GetScalarValue(); } },
{ "messageType", (a, n) => { a.MessageType = n.GetScalarValue(); } },
};
}
}
Loading
Loading