Skip to content

Commit

Permalink
(#18) nuar: update requests processor [pack-all-force]
Browse files Browse the repository at this point in the history
  • Loading branch information
SaintAngeLs committed Oct 6, 2024
1 parent b9b9231 commit 2b7b1d4
Show file tree
Hide file tree
Showing 11 changed files with 189 additions and 138 deletions.
16 changes: 13 additions & 3 deletions src/Nuar/src/Nuar/Extensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,7 @@ private static IServiceCollection AddNuarServices(this IServiceCollection servic
services.AddSingleton<DownstreamHandler>();
services.AddSingleton<ReturnValueHandler>();
services.AddSingleton<WebApiEndpointDefinitions>();


return services;
}
Expand All @@ -176,19 +177,24 @@ private static IServiceCollection AddExtensions(this IServiceCollection services
var extensionProvider = new ExtensionProvider(options);
services.AddSingleton<IExtensionProvider>(extensionProvider);

var logger = services.BuildServiceProvider().GetService<ILogger<ExtensionProvider>>();

foreach (var extension in extensionProvider.GetAll())
{
if (extension.Options.Enabled == false)
if (extension.Options.Enabled == false)
{
logger.LogInformation($"Skipping disabled extension: {extension.Extension.Name}");
continue;
}

logger.LogInformation($"Loading extension: {extension.Extension.Name}");
extension.Extension.Add(services, optionsProvider);
}

return services;
}


public static IApplicationBuilder UseNuar(this IApplicationBuilder app)
{
var newLine = Environment.NewLine;
Expand All @@ -199,7 +205,7 @@ public static IApplicationBuilder UseNuar(this IApplicationBuilder app)
if (options.Auth?.Enabled == true)
{
logger.LogInformation("Authentication is enabled.");
app.UseAuthentication();
app.UseAuthorization();
}
else
{
Expand Down Expand Up @@ -305,7 +311,11 @@ private static void UseExtensions(this IApplicationBuilder app)
}

extension.Extension.Use(app, optionsProvider);
logger.LogInformation($"Enabled extension: '{extension.Extension.Name}'");
var orderMessage = extension.Options.Order.HasValue
? $" [order: {extension.Options.Order}]"
: string.Empty;
logger.LogInformation($"Enabled extension: '{extension.Extension.Name}' " +
$"({extension.Extension.Description}){orderMessage}");
}
}

Expand Down
31 changes: 27 additions & 4 deletions src/Nuar/src/Nuar/Formatters/NetJsonInputFormatter.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
using System;
using System.IO;
using System.Text;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc.Formatters;

namespace Nuar.Formatters
Expand All @@ -19,12 +22,32 @@ protected override bool CanReadType(Type type)
public override async Task<InputFormatterResult> ReadRequestBodyAsync(InputFormatterContext context, Encoding encoding)
{
var request = context.HttpContext.Request;

if (request.Body == null)
{
return await InputFormatterResult.NoValueAsync();
}

using (var reader = new StreamReader(request.Body, encoding))
{
var body = await reader.ReadToEndAsync();
var result = NetJSON.NetJSON.Deserialize(context.ModelType, body);
return await InputFormatterResult.SuccessAsync(result);
try
{
var body = await reader.ReadToEndAsync();
if (string.IsNullOrWhiteSpace(body))
{
return await InputFormatterResult.NoValueAsync();
}

var result = NetJSON.NetJSON.Deserialize(context.ModelType, body);
return await InputFormatterResult.SuccessAsync(result);
}
catch
{
// Handle deserialization error by adding model state error and returning failure
context.ModelState.AddModelError("JSON", "Invalid JSON format.");
return await InputFormatterResult.FailureAsync();
}
}
}
}
}
}
25 changes: 21 additions & 4 deletions src/Nuar/src/Nuar/Formatters/NetJsonOutputFormatter.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
using System;
using System.Text;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc.Formatters;

Expand All @@ -17,11 +19,26 @@ protected override bool CanWriteType(Type type)
return type != null;
}

public override Task WriteResponseBodyAsync(OutputFormatterWriteContext context, Encoding selectedEncoding)
public override async Task WriteResponseBodyAsync(OutputFormatterWriteContext context, Encoding selectedEncoding)
{
var response = context.HttpContext.Response;
var json = NetJSON.NetJSON.Serialize(context.Object);
return response.WriteAsync(json);

// Set Content-Type to application/json
if (!response.Headers.ContainsKey("Content-Type"))
{
response.Headers.Add("Content-Type", "application/json");
}

try
{
var json = NetJSON.NetJSON.Serialize(context.Object);
await response.WriteAsync(json, selectedEncoding);
}
catch
{
// Handle serialization error by returning a failure response or rethrowing the exception
throw new InvalidOperationException("Failed to serialize the response to JSON.");
}
}
}
}
}
178 changes: 91 additions & 87 deletions src/Nuar/src/Nuar/Handlers/DownstreamHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -99,106 +99,110 @@ public async Task HandleAsync(HttpContext context, RouteConfig config)
}

private async Task<HttpResponseMessage> SendRequestAsync(ExecutionData executionData)
{
var httpClient = _httpClientFactory.CreateClient("nuar");
var method = (string.IsNullOrWhiteSpace(executionData.Route.DownstreamMethod)
? executionData.Context.Request.Method
: executionData.Route.DownstreamMethod).ToLowerInvariant();

// Use the downstream URL as is (constructed with the query string in the DownstreamBuilder)
var downstreamUrl = executionData.Downstream;

var request = new HttpRequestMessage
{
RequestUri = new Uri(downstreamUrl)
};

// Forward request headers if specified
if (executionData.Route.ForwardRequestHeaders == true ||
(_options.ForwardRequestHeaders == true && executionData.Route.ForwardRequestHeaders != false))
{
foreach (var (key, value) in executionData.Context.Request.Headers)
{
var httpClient = _httpClientFactory.CreateClient("ntrada");
var method = (string.IsNullOrWhiteSpace(executionData.Route.DownstreamMethod)
? executionData.Context.Request.Method
: executionData.Route.DownstreamMethod).ToLowerInvariant();
request.Headers.TryAddWithoutValidation(key, value.ToArray());
}
}

// Handle custom request headers
var requestHeaders = executionData.Route.RequestHeaders is null || !executionData.Route.RequestHeaders.Any()
? _options.RequestHeaders
: executionData.Route.RequestHeaders;

var request = new HttpRequestMessage
if (requestHeaders != null)
{
foreach (var (key, value) in requestHeaders)
{
if (!string.IsNullOrWhiteSpace(value))
{
RequestUri = new Uri(executionData.Downstream)
};
request.Headers.TryAddWithoutValidation(key, value);
continue;
}

if (executionData.Route.ForwardRequestHeaders == true ||
_options.ForwardRequestHeaders == true && executionData.Route.ForwardRequestHeaders != false)
if (!executionData.Context.Request.Headers.TryGetValue(key, out var values))
{
foreach (var (key, value) in executionData.Context.Request.Headers)
{
request.Headers.TryAddWithoutValidation(key, value.ToArray());
}
continue;
}

var requestHeaders = executionData.Route.RequestHeaders is null ||
!executionData.Route.RequestHeaders.Any()
? _options.RequestHeaders
: executionData.Route.RequestHeaders;
request.Headers.TryAddWithoutValidation(key, values.ToArray());
}
}

if (requestHeaders is {})
{
foreach (var (key, value) in requestHeaders)
{
if (!string.IsNullOrWhiteSpace(value))
{
request.Headers.TryAddWithoutValidation(key, value);
continue;
}
var includeBody = false;
switch (method)
{
case "get":
request.Method = HttpMethod.Get;
break;
case "post":
request.Method = HttpMethod.Post;
includeBody = true;
break;
case "put":
request.Method = HttpMethod.Put;
includeBody = true;
break;
case "patch":
request.Method = HttpMethod.Patch;
includeBody = true;
break;
case "delete":
request.Method = HttpMethod.Delete;
break;
case "head":
request.Method = HttpMethod.Head;
break;
case "options":
request.Method = HttpMethod.Options;
break;
case "trace":
request.Method = HttpMethod.Trace;
break;
default:
return null;
}

if (!executionData.Context.Request.Headers.TryGetValue(key, out var values))
{
continue;
}
// Invoke any HTTP request hooks
if (_httpRequestHooks != null)
{
foreach (var hook in _httpRequestHooks)
{
if (hook == null) continue;
await hook.InvokeAsync(request, executionData);
}
}

request.Headers.TryAddWithoutValidation(key, values.ToArray());
}
}
// Include body content if required (e.g., for POST, PUT, PATCH requests)
if (!includeBody)
{
return await httpClient.SendAsync(request);
}

var includeBody = false;
switch (method)
{
case "get":
request.Method = HttpMethod.Get;
break;
case "post":
request.Method = HttpMethod.Post;
includeBody = true;
break;
case "put":
request.Method = HttpMethod.Put;
includeBody = true;
break;
case "patch":
request.Method = HttpMethod.Patch;
includeBody = true;
break;
case "delete":
request.Method = HttpMethod.Delete;
break;
case "head":
request.Method = HttpMethod.Head;
break;
case "options":
request.Method = HttpMethod.Options;
break;
case "trace":
request.Method = HttpMethod.Trace;
break;
default:
return null;
}

if (_httpRequestHooks is {})
{
foreach (var hook in _httpRequestHooks)
{
if (hook is null)
{
continue;
}
using var content = GetHttpContent(executionData);
request.Content = content;
return await httpClient.SendAsync(request);
}

await hook.InvokeAsync(request, executionData);
}
}

if (!includeBody)
{
return await httpClient.SendAsync(request);
}

using var content = GetHttpContent(executionData);
request.Content = content;
return await httpClient.SendAsync(request);
}

private static HttpContent GetHttpContent(ExecutionData executionData)
{
Expand Down
4 changes: 1 addition & 3 deletions src/Nuar/src/Nuar/Nuar.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -38,11 +38,9 @@
<FrameworkReference Include="Microsoft.AspNetCore.App" />

<PackageReference Include="MessagePack" Version="2.5.172" />
<PackageReference Include="Microsoft.AspNetCore.Authentication" Version="2.2.0" />
<PackageReference Include="Microsoft.AspNetCore.Http" Version="2.2.2" />
<PackageReference Include="Microsoft.AspNetCore.Routing" Version="2.2.2" />
<PackageReference Include="Microsoft.Extensions.Http.Polly" Version="8.0.8" />
<PackageReference Include="NetJSON" Version="1.4.4" />
<PackageReference Include="NJsonSchema" Version="11.0.2" />
<PackageReference Include="NJsonSchema.Yaml" Version="11.0.2" />
<PackageReference Include="System.Runtime.Loader" Version="4.3.0" />
<PackageReference Include="YamlDotNet" Version="16.1.2" />
Expand Down
Loading

0 comments on commit 2b7b1d4

Please sign in to comment.