Skip to content

Commit

Permalink
Refine response definition and generalize logic
Browse files Browse the repository at this point in the history
  • Loading branch information
Kaliumhexacyanoferrat committed Oct 16, 2024
1 parent 8e51e06 commit a806598
Show file tree
Hide file tree
Showing 10 changed files with 131 additions and 47 deletions.
10 changes: 5 additions & 5 deletions Modules/Controllers/Provider/ControllerHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,15 @@

namespace GenHTTP.Modules.Controllers.Provider;

public sealed partial class ControllerHandler : IHandler
public sealed partial class ControllerHandler : IHandler, IServiceMethodProvider
{
private static readonly Regex HyphenMatcher = CreateHyphenMatcher();

#region Get-/Setters

public IHandler Parent { get; }

private MethodCollection Provider { get; }
public MethodCollection Methods { get; }

private ResponseProvider ResponseProvider { get; }

Expand All @@ -38,7 +38,7 @@ public ControllerHandler(IHandler parent, object instance, MethodRegistry regist

ResponseProvider = new ResponseProvider(registry);

Provider = new MethodCollection(this, AnalyzeMethods(instance.GetType(), registry));
Methods = new MethodCollection(this, AnalyzeMethods(instance.GetType(), registry));
}

private IEnumerable<Func<IHandler, MethodHandler>> AnalyzeMethods(Type type, MethodRegistry registry)
Expand Down Expand Up @@ -98,9 +98,9 @@ private List<string> FindPathArguments(MethodInfo method)

#region Functionality

public ValueTask PrepareAsync() => Provider.PrepareAsync();
public ValueTask PrepareAsync() => Methods.PrepareAsync();

public ValueTask<IResponse?> HandleAsync(IRequest request) => Provider.HandleAsync(request);
public ValueTask<IResponse?> HandleAsync(IRequest request) => Methods.HandleAsync(request);

#endregion

Expand Down
2 changes: 1 addition & 1 deletion Modules/Conversion/Serializers/SerializationRegistry.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ public SerializationRegistry(FlexibleContentType defaultType,

private FlexibleContentType Default { get; }

private Dictionary<FlexibleContentType, ISerializationFormat> Formats { get; }
public IReadOnlyDictionary<FlexibleContentType, ISerializationFormat> Formats { get; }

#endregion

Expand Down
2 changes: 1 addition & 1 deletion Modules/Functional/Provider/InlineHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

namespace GenHTTP.Modules.Functional.Provider;

public class InlineHandler : IHandler
public class InlineHandler : IHandler, IServiceMethodProvider
{

#region Get-/Setters
Expand Down
2 changes: 1 addition & 1 deletion Modules/OpenApi/ApiDiscovery.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ public static class ApiDiscovery

public static ApiDiscoveryRegistryBuilder Default() => Empty().Add<ConcernExplorer>()
.Add<LayoutExplorer>()
.Add<InlineExplorer>()
.Add<ServiceExplorer>()
.Add<MethodCollectionExplorer>()
.Add<MethodHandlerExplorer>();

Expand Down
21 changes: 0 additions & 21 deletions Modules/OpenApi/Discovery/InlineExplorer.cs

This file was deleted.

102 changes: 89 additions & 13 deletions Modules/OpenApi/Discovery/MethodHandlerExplorer.cs
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
using System.Text;

using GenHTTP.Api.Content;
using GenHTTP.Api.Protocol;
using GenHTTP.Modules.Reflection;
using GenHTTP.Modules.Reflection.Operations;

using NJsonSchema;
using NSwag;

Expand Down Expand Up @@ -58,24 +60,17 @@ public void Explore(IHandler handler, List<string> path, OpenApiDocument documen
operation.Parameters.Add(param);
}

var response = new OpenApiResponse();

var media = new OpenApiMediaType();

media.Schema = JsonSchema.FromType(methodHandler.Operation.Method.ReturnType);

response.Content.Add("application/json", media);

// todo: methodHandler.Registry.Formatting.Formatters

operation.Responses.Add("200", response);
foreach (var (key, value) in GetResponses(methodHandler.Operation, methodHandler.Registry))
{
operation.Responses.Add(key, value);
}

pathItem.Add(method.RawMethod, operation);
}
}
}

private OpenApiPathItem GetPathItem(OpenApiDocument document, List<string> path, Operation operation)
private static OpenApiPathItem GetPathItem(OpenApiDocument document, List<string> path, Operation operation)
{
var stringPath = BuildPath(operation.Path.Name, path);

Expand Down Expand Up @@ -129,7 +124,7 @@ private static string BuildPath(string name, List<string> pathParts)
_ => false
};

private string? GetTag(Operation operation)
private static string? GetTag(Operation operation)
{
var type = operation.Method.DeclaringType?.Name;

Expand All @@ -141,4 +136,85 @@ private static string BuildPath(string name, List<string> pathParts)
return null;
}

private static Dictionary<string, OpenApiResponse> GetResponses(Operation operation, MethodRegistry registry)
{
var result = new Dictionary<string, OpenApiResponse>();

var sink = operation.Result.Sink;
var type = operation.Result.Type;

if (sink == OperationResultSink.None || MightBeNull(type))
{
result.Add("204", new OpenApiResponse()
{
Description = "A response containing no body"
});
}

if (sink == OperationResultSink.Formatter)
{
result.Add("200", GetResponse(type, "text/plain"));
}
else if (sink == OperationResultSink.Serializer)
{
result.Add("200", GetResponse(type, registry.Serialization.Formats.Select(s => s.Key.RawType).ToArray()));
}
else if (sink == OperationResultSink.Stream)
{
var response = new OpenApiResponse()
{
Description = "A dynamically generated response"
};

var schema = new JsonSchema()
{
Format = "binary"
};

response.Content.Add("application/octet-stream", new OpenApiMediaType() { Schema = schema });

result.Add("200", response);
}
else if (sink == OperationResultSink.Dynamic)
{
var response = new OpenApiResponse()
{
Description = "A dynamically generated response"
};

response.Content.Add("*/*", new OpenApiMediaType());

result.Add("200", response);
}

return result;
}

private static bool MightBeNull(Type type)
{
if (type.IsClass)
{
return true;
}

return Nullable.GetUnderlyingType(type) != null;
}

private static OpenApiResponse GetResponse(Type type, params string[] mediaTypes)
{
var response = new OpenApiResponse();

foreach (var mediaType in mediaTypes)
{
var media = new OpenApiMediaType
{
Schema = JsonSchema.FromType(type)
};

response.Content.Add(mediaType, media);
}

return response;
}

}
22 changes: 22 additions & 0 deletions Modules/OpenApi/Discovery/ServiceExplorer.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
using GenHTTP.Api.Content;

using GenHTTP.Modules.Reflection;

using NSwag;

namespace GenHTTP.Modules.OpenApi.Discovery;

public class ServiceExplorer : IApiExplorer
{

public bool CanExplore(IHandler handler) => handler is IServiceMethodProvider;

public void Explore(IHandler handler, List<string> path, OpenApiDocument document, ApiDiscoveryRegistry registry)
{
if (handler is IServiceMethodProvider serviceProvider)
{
registry.Explore(serviceProvider.Methods, path, document);
}
}

}
4 changes: 1 addition & 3 deletions Modules/OpenApi/GenHTTP.Modules.OpenApi.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,6 @@

<ProjectReference Include="..\..\API\GenHTTP.Api.csproj"/>

<ProjectReference Include="..\Functional\GenHTTP.Modules.Functional.csproj" />

<ProjectReference Include="..\Layouting\GenHTTP.Modules.Layouting.csproj" />

<ProjectReference Include="..\Reflection\GenHTTP.Modules.Reflection.csproj" />
Expand All @@ -55,7 +53,7 @@
<PackageReference Include="NSwag.Core.Yaml" Version="14.1.0" />

<PackageReference Include="NSwag.Generation" Version="14.1.0" />

<PackageReference Include="Microsoft.SourceLink.GitHub" Version="8.0.0" PrivateAssets="All"/>

</ItemGroup>
Expand Down
8 changes: 8 additions & 0 deletions Modules/Reflection/IServiceMethodProvider.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
namespace GenHTTP.Modules.Reflection;

public interface IServiceMethodProvider
{

MethodCollection Methods { get; }

}
5 changes: 3 additions & 2 deletions Modules/Webservices/Provider/ServiceResourceRouter.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System.Reflection;

using GenHTTP.Api.Content;
using GenHTTP.Api.Protocol;

Expand All @@ -7,12 +8,12 @@

namespace GenHTTP.Modules.Webservices.Provider;

public sealed class ServiceResourceRouter : IHandler
public sealed class ServiceResourceRouter : IHandler, IServiceMethodProvider
{

#region Get-/Setters

private MethodCollection Methods { get; }
public MethodCollection Methods { get; }

public IHandler Parent { get; }

Expand Down

0 comments on commit a806598

Please sign in to comment.