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: allow external references (without resolution) #131

Closed
wants to merge 7 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
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
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
# [4.1.0](https://github.com/LEGO/AsyncAPI.NET/compare/v4.0.2...v4.1.0) (2023-09-27)


### Features

* **bindings:** update FilterPolicy to match AWS API ([#128](https://github.com/LEGO/AsyncAPI.NET/issues/128)) ([5b64654](https://github.com/LEGO/AsyncAPI.NET/commit/5b6465474ae09d42a27377bf04d58fdbd1dd8a59))

## [4.0.2](https://github.com/LEGO/AsyncAPI.NET/compare/v4.0.1...v4.0.2) (2023-08-01)


Expand Down
18 changes: 16 additions & 2 deletions src/LEGO.AsyncAPI.Bindings/Sns/Consumer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ namespace LEGO.AsyncAPI.Bindings.Sns
using System;
using System.Collections.Generic;
using LEGO.AsyncAPI.Attributes;
using LEGO.AsyncAPI.Models;
using LEGO.AsyncAPI.Models.Interfaces;
using LEGO.AsyncAPI.Writers;

Expand All @@ -20,8 +21,14 @@ public class Consumer : IAsyncApiExtensible

/// <summary>
/// Only receive a subset of messages from the channel, determined by this policy.
/// Depending on the FilterPolicyScope, a map of either a message attribute or message body to an array of possible matches. The match may be a simple string for an exact match, but it may also be an object that represents a constraint and values for that constraint.
/// </summary>
public FilterPolicy FilterPolicy { get; set; }
public AsyncApiAny FilterPolicy { get; set; }

/// <summary>
/// Determines whether the FilterPolicy applies to MessageAttributes or MessageBody.
/// </summary>
public FilterPolicyScope FilterPolicyScope { get; set; }

/// <summary>
/// If true AWS SNS attributes are removed from the body, and for SQS, SNS message attributes are copied to SQS message attributes. If false the SNS attributes are included in the body.
Expand Down Expand Up @@ -55,7 +62,8 @@ public void Serialize(IAsyncApiWriter writer)
writer.WriteStartObject();
writer.WriteRequiredProperty("protocol", this.Protocol.GetDisplayName());
writer.WriteRequiredObject("endpoint", this.Endpoint, (w, e) => e.Serialize(w));
writer.WriteOptionalObject("filterPolicy", this.FilterPolicy, (w, f) => f.Serialize(w));
writer.WriteOptionalObject("filterPolicy", this.FilterPolicy, (w, f) => f.Write(w));
writer.WriteOptionalProperty("filterPolicyScope", this.FilterPolicyScope.GetDisplayName());
writer.WriteRequiredProperty("rawMessageDelivery", this.RawMessageDelivery);
writer.WriteOptionalObject("redrivePolicy", this.RedrivePolicy, (w, p) => p.Serialize(w));
writer.WriteOptionalObject("deliveryPolicy", this.DeliveryPolicy, (w, p) => p.Serialize(w));
Expand All @@ -77,4 +85,10 @@ public enum Protocol
[Display("lambda")] Lambda,
[Display("firehose")] Firehose,
}

public enum FilterPolicyScope
{
[Display("MessageAttributes")] MessageAttributes,
[Display("MessageBody")] MessageBody,
}
}
31 changes: 0 additions & 31 deletions src/LEGO.AsyncAPI.Bindings/Sns/FilterPolicy.cs

This file was deleted.

8 changes: 2 additions & 6 deletions src/LEGO.AsyncAPI.Bindings/Sns/SnsOperationBinding.cs
Original file line number Diff line number Diff line change
Expand Up @@ -47,18 +47,14 @@ public class SnsOperationBinding : OperationBinding<SnsOperationBinding>
{
{ "protocol", (a, n) => { a.Protocol = n.GetScalarValue().GetEnumFromDisplayName<Protocol>(); } },
{ "endpoint", (a, n) => { a.Endpoint = n.ParseMapWithExtensions(this.identifierFixFields); } },
{ "filterPolicy", (a, n) => { a.FilterPolicy = n.ParseMapWithExtensions(this.filterPolicyFixedFields); } },
{ "filterPolicy", (a, n) => { a.FilterPolicy = n.CreateAny(); } },
{ "filterPolicyScope", (a, n) => { a.FilterPolicyScope = n.GetScalarValue().GetEnumFromDisplayName<FilterPolicyScope>(); } },
{ "rawMessageDelivery", (a, n) => { a.RawMessageDelivery = n.GetBooleanValue(); } },
{ "redrivePolicy", (a, n) => { a.RedrivePolicy = n.ParseMapWithExtensions(this.redrivePolicyFixedFields); } },
{ "deliveryPolicy", (a, n) => { a.DeliveryPolicy = n.ParseMapWithExtensions(this.deliveryPolicyFixedFields); } },
{ "displayName", (a, n) => { a.DisplayName = n.GetScalarValue(); } },
};

private FixedFieldMap<FilterPolicy> filterPolicyFixedFields => new()
{
{ "attributes", (a, n) => { a.Attributes = n.CreateAny(); } },
};

private FixedFieldMap<RedrivePolicy> redrivePolicyFixedFields => new()
{
{ "deadLetterQueue", (a, n) => { a.DeadLetterQueue = n.ParseMapWithExtensions(identifierFixFields); } },
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
// Copyright (c) The LEGO Group. All rights reserved.
// Copyright (c) The LEGO Group. All rights reserved.

namespace LEGO.AsyncAPI.Readers
{
using System.Collections.Generic;
using System.Linq;
using System.Text.Json.Nodes;
using System.Threading;
using System.Threading.Tasks;
using LEGO.AsyncAPI.Exceptions;
using LEGO.AsyncAPI.Extensions;
Expand Down Expand Up @@ -76,7 +77,7 @@ public AsyncApiDocument Read(JsonNode input, out AsyncApiDiagnostic diagnostic)
return document;
}

public Task<ReadResult> ReadAsync(JsonNode input)
public async Task<ReadResult> ReadAsync(JsonNode input, CancellationToken cancellationToken = default)
{
var diagnostic = new AsyncApiDiagnostic();
var context = new ParsingContext(diagnostic)
Expand Down Expand Up @@ -106,11 +107,11 @@ public Task<ReadResult> ReadAsync(JsonNode input)
}
}

return Task.FromResult(new ReadResult
return new ReadResult
{
AsyncApiDocument = document,
AsyncApiDiagnostic = diagnostic,
});
};
}

private void ResolveReferences(AsyncApiDiagnostic diagnostic, AsyncApiDocument document)
Expand Down
2 changes: 1 addition & 1 deletion src/LEGO.AsyncAPI.Readers/AsyncApiReaderSettings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ public enum ReferenceResolutionSetting
DoNotResolveReferences,

/// <summary>
/// ResolveAllReferences, effectively inlining them.
/// Resolve internal component references and inline them.
/// </summary>
ResolveReferences,
}
Expand Down
28 changes: 22 additions & 6 deletions src/LEGO.AsyncAPI.Readers/V2/AsyncApiV2VersionService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -67,9 +67,21 @@ public AsyncApiReference ConvertToAsyncApiReference(
Id = reference,
};
}

var asyncApiReference = new AsyncApiReference();
if (reference.StartsWith("/"))
{
asyncApiReference.IsFragment = true;
}

asyncApiReference.ExternalResource = segments[0];

return asyncApiReference;

}
else if (segments.Length == 2)
{
// Local reference
if (reference.StartsWith("#"))
{
try
Expand All @@ -84,7 +96,7 @@ public AsyncApiReference ConvertToAsyncApiReference(
}

var id = segments[1];

var asyncApiReference = new AsyncApiReference();
if (id.StartsWith("/components/"))
{
var localSegments = segments[1].Split('/');
Expand All @@ -103,12 +115,16 @@ public AsyncApiReference ConvertToAsyncApiReference(

id = localSegments[3];
}

return new AsyncApiReference
else
{
Type = type,
Id = id,
};
asyncApiReference.IsFragment = true;
}

asyncApiReference.ExternalResource = segments[0];
asyncApiReference.Type = type;
asyncApiReference.Id = id;

return asyncApiReference;
}
}

Expand Down
2 changes: 1 addition & 1 deletion src/LEGO.AsyncAPI/Models/AsyncApiDocument.cs
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,7 @@ internal T ResolveReference<T>(AsyncApiReference reference) where T : class, IAs
return this.ResolveReference(reference) as T;
}

public IAsyncApiReferenceable ResolveReference(AsyncApiReference reference)
internal IAsyncApiReferenceable ResolveReference(AsyncApiReference reference)
{
if (reference == null)
{
Expand Down
45 changes: 44 additions & 1 deletion src/LEGO.AsyncAPI/Models/AsyncApiReference.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,14 @@ namespace LEGO.AsyncAPI.Models
/// </summary>
public class AsyncApiReference : IAsyncApiSerializable
{
/// <summary>
/// External resource in the reference.
/// It maybe:
/// 1. a absolute/relative file path, for example: ../commons/pet.json
/// 2. a Url, for example: http://localhost/pet.json
/// </summary>
public string ExternalResource { get; set; }

/// <summary>
/// Gets or sets the element type referenced.
/// </summary>
Expand All @@ -27,17 +35,37 @@ public class AsyncApiReference : IAsyncApiSerializable
public AsyncApiDocument HostDocument { get; set; } = null;

/// <summary>
/// Gets the full reference string for v2.3.
/// Gets a flag indicating whether a file is a valid OpenAPI document or a fragment
/// </summary>
public bool IsFragment { get; set; } = false;

/// <summary>
/// Gets a flag indicating whether this reference is an external reference.
/// </summary>
public bool IsExternal => this.ExternalResource != null;

/// <summary>
/// Gets the full reference string for v2.
/// </summary>
public string Reference
{
get
{
if (this.IsExternal)
{
return this.GetExternalReferenceV2();
}

if (!this.Type.HasValue)
{
throw new ArgumentNullException(nameof(this.Type));
}

//if (this.Type == ReferenceType.SecurityScheme)
//{
// return this.Id;
//}

return "#/components/" + this.Type.GetDisplayName() + "/" + this.Id;
}
}
Expand Down Expand Up @@ -67,6 +95,21 @@ public void SerializeV2(IAsyncApiWriter writer)
writer.WriteEndObject();
}

private string GetExternalReferenceV2()
{
if (this.Id != null)
{
if (this.IsFragment)
{
return this.ExternalResource + "#" + this.Id;
}

return this.ExternalResource + "#/components/" + this.Type.GetDisplayName() + "/" + this.Id;
}

return this.ExternalResource;
}

public void Write(IAsyncApiWriter writer)
{
this.SerializeV2(writer);
Expand Down
15 changes: 12 additions & 3 deletions src/LEGO.AsyncAPI/Services/AsyncApiReferenceResolver.cs
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,7 @@ public override void Visit(AsyncApiSchema schema)
this.ResolveMap(schema.Properties);
}

private void ResolveObject<T>(T entity, Action<T> assign) where T : class, IAsyncApiReferenceable
private void ResolveObject<T>(T entity, Action<T> assign) where T : class, IAsyncApiReferenceable, new()
{
if (entity == null)
{
Expand Down Expand Up @@ -184,7 +184,7 @@ private void ResolveObject<T>(T entity, Action<T> assign) where T : class, IAsyn
}
}

private void ResolveMap<T>(IDictionary<string, T> map) where T : class, IAsyncApiReferenceable
private void ResolveMap<T>(IDictionary<string, T> map) where T : class, IAsyncApiReferenceable, new()
{
if (map == null)
{
Expand All @@ -201,8 +201,17 @@ private void ResolveMap<T>(IDictionary<string, T> map) where T : class, IAsyncAp
}
}

private T ResolveReference<T>(AsyncApiReference reference) where T : class, IAsyncApiReferenceable
private T ResolveReference<T>(AsyncApiReference reference) where T : class, IAsyncApiReferenceable, new()
{
if (reference.IsExternal)
{
return new ()
{
UnresolvedReference = true,
Reference = reference,
};
}

try
{
return this.currentDocument.ResolveReference(reference) as T;
Expand Down
Loading
Loading