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

LEGO DTO #221

Merged
merged 33 commits into from
Aug 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
bd0808e
A very dirty draft - LEGO DTO
yurvon-screamo Jul 8, 2024
2a634b4
Merge branch 'main' of https://github.com/AsyncApi/saunter into featu…
yurvon-screamo Jul 8, 2024
54515c5
Fix recursive type schema generator
yurvon-screamo Jul 8, 2024
3758b5d
Fix recursive type schema generator
yurvon-screamo Jul 8, 2024
2b8ac10
Recovery tests
yurvon-screamo Jul 9, 2024
ab74274
fmt
yurvon-screamo Jul 9, 2024
4ca014d
add union channels
yurvon-screamo Jul 9, 2024
315f906
fix deps
yurvon-screamo Jul 9, 2024
7839b6f
fix deps
yurvon-screamo Jul 9, 2024
fee9ef4
fix deps
yurvon-screamo Jul 9, 2024
9803299
fix deps
yurvon-screamo Jul 9, 2024
b75d512
fix deps
yurvon-screamo Jul 9, 2024
a846652
fix deps
yurvon-screamo Jul 9, 2024
82d7e8e
fix deps
yurvon-screamo Jul 9, 2024
47ad1d9
fix deps
yurvon-screamo Jul 9, 2024
7117391
fix deps on CI
yurvon-screamo Jul 9, 2024
2625b70
fix deps on CI
yurvon-screamo Jul 9, 2024
995bf67
add loop type handle
yurvon-screamo Jul 9, 2024
ff95e41
more units
yurvon-screamo Jul 9, 2024
e683193
recovery integrations
yurvon-screamo Jul 9, 2024
a8ac877
recovery integrations
yurvon-screamo Jul 9, 2024
99a06c1
add to changelog
yurvon-screamo Jul 9, 2024
dd8142d
add test
yurvon-screamo Jul 19, 2024
2c952f9
Migration to LEGO AsyncApi.Net guid
yurvon-screamo Jul 19, 2024
f0c2bf5
Translation to component ref
yurvon-screamo Jul 29, 2024
34587b2
fmt
yurvon-screamo Jul 29, 2024
139b3a9
main merge
yurvon-screamo Aug 8, 2024
77b4b49
bindings to example
yurvon-screamo Aug 8, 2024
dacc7d8
fmt
yurvon-screamo Aug 8, 2024
c03cf70
unit with bindings
yurvon-screamo Aug 8, 2024
5056cb5
unit with bindings
yurvon-screamo Aug 8, 2024
8d7b65e
bindings to docs
yurvon-screamo Aug 8, 2024
66240f8
fix serialize bindings
yurvon-screamo Aug 8, 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
30 changes: 30 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
**/.classpath
**/.dockerignore
**/.env
**/.git
**/.gitignore
**/.project
**/.settings
**/.toolstarget
**/.vs
**/.vscode
**/*.*proj.user
**/*.dbmdl
**/*.jfm
**/azds.yaml
**/bin
**/charts
**/docker-compose*
**/Dockerfile*
**/node_modules
**/npm-debug.log
**/obj
**/secrets.dev.yaml
**/values.dev.yaml
LICENSE
README.md
!**/.gitignore
!.git/HEAD
!.git/config
!.git/packed-refs
!.git/refs/heads/**
2 changes: 1 addition & 1 deletion .github/dotnet/action.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,4 @@ runs:
id: setup-dotnet
uses: actions/setup-dotnet@v1
with:
dotnet-version: "6.0.x"
dotnet-version: "6.0.423"
10 changes: 8 additions & 2 deletions .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,14 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: setup dotnet
uses: ./.github/dotnet

# bug of format tool in dotnet 6
- name: setup
id: setup-dotnet
uses: actions/setup-dotnet@v1
with:
dotnet-version: "8.0.300"

- name: dotnet format check
run: dotnet format --verify-no-changes *.sln
env:
Expand Down
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,17 @@
# Changelog

All notable changes to this project will be documented in this file.

The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)

<!-- Please update the links section at the bottom when adding a new version. -->

## [v0.14.0] - ?
### Changed
- [Change AsyncApi data structure to LEGO AsyncAPI.NET](https://github.com/m-wild/saunter/issues/188)
- [Replace NJsonSchema with own implementation](https://github.com/m-wild/saunter/issues/188)
- [Allow usages of the annotation attributes on interfaces](https://github.com/m-wild/saunter/issues/213)
- Bump ws from 7.5.3 to 7.5.10 in /src/Saunter.UI

## [v0.13.0] - 2024-01-16
### Changed
Expand Down
125 changes: 70 additions & 55 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Saunter

![CI](https://github.com/tehmantra/saunter/workflows/CI/badge.svg)
![CI](https://github.com/asyncapi/saunter/workflows/CI/badge.svg)
[![NuGet Badge](https://buildstats.info/nuget/saunter?includePreReleases=true)](https://www.nuget.org/packages/Saunter/)

Saunter is an [AsyncAPI](https://github.com/asyncapi/asyncapi) documentation generator for dotnet.
Expand All @@ -11,7 +11,7 @@ Saunter is an [AsyncAPI](https://github.com/asyncapi/asyncapi) documentation gen

## Getting Started

See [examples/StreetlightsAPI](https://github.com/tehmantra/saunter/blob/main/examples/StreetlightsAPI).
See [examples/StreetlightsAPI](https://github.com/asyncapi/saunter/tree/main/examples/StreetlightsAPI).


1. Install the Saunter package
Expand All @@ -27,25 +27,30 @@ See [examples/StreetlightsAPI](https://github.com/tehmantra/saunter/blob/main/ex
services.AddAsyncApiSchemaGeneration(options =>
{
// Specify example type(s) from assemblies to scan.
options.AssemblyMarkerTypes = new[] {typeof(StreetlightMessageBus)};

options.AssemblyMarkerTypes = new[] { typeof(StreetlightMessageBus) };
// Build as much (or as little) of the AsyncApi document as you like.
// Saunter will generate Channels, Operations, Messages, etc, but you
// may want to specify Info here.
options.Middleware.UiTitle = "Streetlights API";
options.AsyncApi = new AsyncApiDocument
{
Info = new Info("Streetlights API", "1.0.0")
Info = new AsyncApiInfo()
{
Description = "The Smartylighting Streetlights API allows you\nto remotely manage the city lights.",
License = new License("Apache 2.0")
Title = "Streetlights API",
Version = "1.0.0",
Description = "The Smartylighting Streetlights API allows you to remotely manage the city lights.",
License = new AsyncApiLicense()
{
Url = "https://www.apache.org/licenses/LICENSE-2.0"
Name = "Apache 2.0",
Url = new("https://www.apache.org/licenses/LICENSE-2.0"),
}
},
Servers =
{
{ "mosquitto", new Server("test.mosquitto.org", "mqtt") }
}
["mosquitto"] = new AsyncApiServer(){ Url = "test.mosquitto.org", Protocol = "mqtt"},
["webapi"] = new AsyncApiServer(){ Url = "localhost:5000", Protocol = "http"},
},
};
});
```
Expand All @@ -56,9 +61,11 @@ See [examples/StreetlightsAPI](https://github.com/tehmantra/saunter/blob/main/ex
[AsyncApi] // Tells Saunter to scan this class.
public class StreetlightMessageBus : IStreetlightMessageBus
{
[Channel("publish/light/measured")] // Creates a Channel
[PublishOperation(typeof(LightMeasuredEvent), Summary = "Inform about environmental lighting conditions for a particular streetlight.")] // A simple Publish operation.
public void PublishLightMeasuredEvent(Streetlight streetlight, int lumens) {}
private const string SubscribeLightMeasuredTopic = "subscribe/light/measured";

[Channel(SubscribeLightMeasuredTopic, Servers = new[] { "mosquitto" })]
[SubscribeOperation(typeof(LightMeasuredEvent), "Light", Summary = "Subscribe to environmental lighting conditions for a particular streetlight.")]
public void PublishLightMeasuredEvent(Streetlight streetlight, int lumens) {}
```

4. Add saunter middleware to host the AsyncApi json document. In the `Configure` method of `Startup.cs`:
Expand All @@ -68,6 +75,8 @@ See [examples/StreetlightsAPI](https://github.com/tehmantra/saunter/blob/main/ex
{
endpoints.MapAsyncApiDocuments();
endpoints.MapAsyncApiUi();

endpoints.MapControllers();
});
```

Expand Down Expand Up @@ -96,11 +105,11 @@ See [examples/StreetlightsAPI](https://github.com/tehmantra/saunter/blob/main/ex

6. Use the published AsyncAPI UI:

![AsyncAPI UI](https://raw.githubusercontent.com/tehmantra/saunter/main/assets/asyncapi-ui-screenshot.png)
![AsyncAPI UI](https://raw.githubusercontent.com/asyncapi/saunter/main/assets/asyncapi-ui-screenshot.png)
## Configuration

See [the options source code](https://github.com/tehmantra/saunter/blob/main/src/Saunter/AsyncApiOptions.cs) for detailed info.
See [the options source code](https://github.com/asyncapi/saunter/blob/main/src/Saunter/AsyncApiOptions.cs) for detailed info.
Common options are below:

Expand All @@ -109,7 +118,7 @@ services.AddAsyncApiSchemaGeneration(options =>
{
options.AssemblyMarkerTypes = new[] { typeof(Startup) }; // Tell Saunter where to scan for your classes.
options.AddChannelItemFilter<MyChannelItemFilter>(); // Dynamically update ChanelItems
options.AddChannelFilter<MyAsyncApiChannelFilter>(); // Dynamically update ChanelItems
options.AddOperationFilter<MyOperationFilter>(); // Dynamically update Operations
options.Middleware.Route = "/asyncapi/asyncapi.json"; // AsyncAPI JSON document URL
Expand All @@ -118,30 +127,6 @@ services.AddAsyncApiSchemaGeneration(options =>
}
```


## JSON Schema Settings

The JSON schema generation can be customized using the `options.JsonSchemaGeneratorSettings`. Saunter defaults to the popular `camelCase` naming strategy for both properties and types.

For example, setting to use PascalCase:

```c#
services.AddAsyncApiSchemaGeneration(options =>
{
options.JsonSchemaGeneratorSettings.TypeNameGenerator = new DefaultTypeNameGenerator();

// Note: need to assign a new JsonSerializerSettings, not just set the properties within it.
options.JsonSchemaGeneratorSettings.SerializerSettings = new JsonSerializerSettings
{
ContractResolver = new DefaultContractResolver(),
Formatting = Formatting.Indented;
};
}
```

You have access to the full range of both [NJsonSchema](https://github.com/RicoSuter/NJsonSchema) and [JSON.NET](https://github.com/JamesNK/Newtonsoft.Json) settings to configure the JSON schema generation, including custom ContractResolvers.

## Bindings

Bindings are used to describe protocol specific information. These can be added to the AsyncAPI document and then applied to different components by setting the `BindingsRef` property in the relevant attributes `[OperationAttribute]`, `[MessageAttribute]`, `[ChannelAttribute]`
Expand All @@ -155,17 +140,31 @@ services.AddAsyncApiSchemaGeneration(options =>
{
Components =
{
ChannelBindings =
ChannelBindings =
{
["my-amqp-binding"] = new ChannelBindings
["amqpDev"] = new()
{
Amqp = new AmqpChannelBinding
new AMQPChannelBinding
{
Is = AmqpChannelBindingIs.RoutingKey,
Exchange = new AmqpChannelBindingExchange
Is = ChannelType.Queue,
Exchange = new()
{
Name = "example-exchange",
VirtualHost = "/development"
Vhost = "/development"
}
}
}
},
OperationBindings =
{
{
"postBind",
new()
{
new HttpOperationBinding
{
Method = "POST",
Type = HttpOperationType.Response,
}
}
}
Expand All @@ -176,16 +175,16 @@ services.AddAsyncApiSchemaGeneration(options =>
```

```csharp
[Channel("light.measured", BindingsRef = "my-amqp-binding")] // Set the BindingsRef property
[Channel("light.measured", BindingsRef = "amqpDev")] // Set the BindingsRef property
public void PublishLightMeasuredEvent(Streetlight streetlight, int lumens) {}
```

Available bindings:
* [AMQP](https://github.com/tehmantra/saunter/tree/main/src/Saunter/AsyncApiSchema/v2/Bindings/Amqp)
* [HTTP](https://github.com/tehmantra/saunter/tree/main/src/Saunter/AsyncApiSchema/v2/Bindings/Http)
* [Kafka](https://github.com/tehmantra/saunter/tree/main/src/Saunter/AsyncApiSchema/v2/Bindings/Kafka)
* [MQTT](https://github.com/tehmantra/saunter/tree/main/src/Saunter/AsyncApiSchema/v2/Bindings/Mqtt)
```csharp
[PublishOperation(typeof(LightMeasuredEvent), "Light", BindingsRef = "postBind")]
public void MeasureLight([FromBody] LightMeasuredEvent lightMeasuredEvent)
```

Available bindings: https://www.nuget.org/packages/AsyncAPI.NET.Bindings/
## Multiple AsyncAPI documents

Expand Down Expand Up @@ -250,10 +249,27 @@ Each document can be accessed by specifying the name in the URL
}
```

## Migration to LEGO AsyncApi.Net

When switching to the LEGO AsyncApi.Net, we broke the public API.

To simplify the transition to new versions of the library, this note was created.

What was broken:

* Namespaces have changed:
* Saunter.AsyncApiSchema.v2 -> LEGO.AsyncAPI.Models
* Saunter.Attributes; -> Saunter.AttributeProvider.Attributes
* Change the name of the data structures, add prefix 'AsyncApi' (example 'class Info' -> 'class AsyncApiInfo')
* All data structure constructors are now with the parameterless constructor

There was no more significant changes on public API.

Keep this in mind when planning the migration process.

## Contributing

See our [contributing guide](https://github.com/tehmantra/saunter/blob/main/CONTRIBUTING.md/CONTRIBUTING.md).
See our [contributing guide](https://github.com/asyncapi/saunter/blob/main/CONTRIBUTING.md/CONTRIBUTING.md).
Feel free to get involved in the project by opening issues, or submitting pull requests.

Expand All @@ -262,5 +278,4 @@ You can also find me on the [AsyncAPI community slack](https://asyncapi.com/slac
## Thanks

* This project is heavily inspired by [Swashbuckle](https://github.com/domaindrivendev/Swashbuckle.AspNetCore).
* We use [NJsonSchema](https://github.com/RicoSuter/NJsonSchema) for the JSON schema heavy lifting,
* We use [LEGO AsyncAPI.NET](https://github.com/LEGO/AsyncAPI.NET) schema and serializing.
17 changes: 8 additions & 9 deletions examples/StreetlightsAPI/API.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
using System.Text.Json;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
using Saunter.Attributes;
using Saunter.AttributeProvider.Attributes;

namespace StreetlightsAPI
{
Expand Down Expand Up @@ -51,10 +51,9 @@ public class StreetlightsController
{
private const string PublishLightMeasuredTopic = "publish/light/measured";


// Simulate a database of streetlights
private static int StreetlightSeq = 2;
private static readonly List<Streetlight> StreetlightDatabase = new List<Streetlight>
private static int s_streetlightSeq = 2;
private static readonly List<Streetlight> s_streetlightDatabase = new()
{
new Streetlight { Id = 1, Position = new [] { -36.320320, 175.485986 }, LightIntensity = new() },
};
Expand All @@ -73,7 +72,7 @@ public StreetlightsController(IStreetlightMessageBus streetlightMessageBus, ILog
/// </summary>
[HttpGet]
[Route("api/streetlights")]
public IEnumerable<Streetlight> Get() => StreetlightDatabase;
public IEnumerable<Streetlight> Get() => s_streetlightDatabase;

/// <summary>
/// Add a new streetlight
Expand All @@ -82,16 +81,16 @@ public StreetlightsController(IStreetlightMessageBus streetlightMessageBus, ILog
[Route("api/streetlights")]
public Streetlight Add([FromBody] Streetlight streetlight)
{
streetlight.Id = StreetlightSeq++;
StreetlightDatabase.Add(streetlight);
streetlight.Id = s_streetlightSeq++;
s_streetlightDatabase.Add(streetlight);
return streetlight;
}

/// <summary>
/// Inform about environmental lighting conditions for a particular streetlight.
/// </summary>
[Channel(PublishLightMeasuredTopic, Servers = new[] { "webapi" })]
[PublishOperation(typeof(LightMeasuredEvent), "Light")]
[PublishOperation(typeof(LightMeasuredEvent), "Light", BindingsRef = "postBind")]
[HttpPost]
[Route(PublishLightMeasuredTopic)]
public void MeasureLight([FromBody] LightMeasuredEvent lightMeasuredEvent)
Expand All @@ -102,7 +101,7 @@ public void MeasureLight([FromBody] LightMeasuredEvent lightMeasuredEvent)

_logger.LogInformation("Received message on {Topic} with payload {Payload} ", PublishLightMeasuredTopic, payload);

var streetlight = StreetlightDatabase.SingleOrDefault(s => s.Id == lightMeasuredEvent.Id);
var streetlight = s_streetlightDatabase.SingleOrDefault(s => s.Id == lightMeasuredEvent.Id);
if (streetlight != null)
{
streetlight.LightIntensity.Add(new(lightMeasuredEvent.SentAt, lightMeasuredEvent.Lumens));
Expand Down
4 changes: 2 additions & 2 deletions examples/StreetlightsAPI/Messaging.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
using System.Text.Json;
using Microsoft.Extensions.Logging;
using Saunter.Attributes;
using Saunter.AttributeProvider.Attributes;

namespace StreetlightsAPI
{
Expand All @@ -21,7 +21,7 @@ public StreetlightMessageBus(ILoggerFactory logger)
_logger = logger.CreateLogger("Streetlight");
}

[Channel(SubscribeLightMeasuredTopic, Servers = new[] { "mosquitto" })]
[Channel(SubscribeLightMeasuredTopic, Servers = new[] { "mosquitto" }, BindingsRef = "amqpDev")]
[SubscribeOperation(typeof(LightMeasuredEvent), "Light", Summary = "Subscribe to environmental lighting conditions for a particular streetlight.")]
public void PublishLightMeasurement(LightMeasuredEvent lightMeasuredEvent)
{
Expand Down
Loading
Loading