Skip to content

Commit

Permalink
Merge pull request #24 from Worth-NL/enhancement/ApiControllers
Browse files Browse the repository at this point in the history
Enhancement/api controllers
  • Loading branch information
Thomas-M-Krystyan authored Apr 19, 2024
2 parents fc2a656 + af4fd3a commit 881f6b2
Show file tree
Hide file tree
Showing 15 changed files with 123 additions and 167 deletions.
2 changes: 1 addition & 1 deletion Documentation/OMC - Documentation.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# OMC Documentation

v.1.6.7
v.1.6.8

© 2024, Worth Systems.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ public override void OnResultExecuting(ResultExecutingContext context)
var responder = context.HttpContext.RequestServices.GetRequiredService(serviceType) as IRespondingService;

// Intercepting and replacing native error messages by user-friendly API responses
context = responder?.GetStandardized_Exception_ActionResult(context, details!.Errors) ?? context;
context = responder?.Get_Exception_ActionResult(context, details!.Errors) ?? context;
}
else
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ namespace EventsHandler.Behaviors.Responding.Messages.Models.Errors
/// <summary>
/// A HTTP Request failed.
/// </summary>
/// <seealso cref="BaseApiStandardResponseBody"/>
/// <seealso cref="BaseEnhancedStandardResponseBody"/>
internal sealed class HttpRequestFailed : BaseEnhancedStandardResponseBody
{
/// <summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ namespace EventsHandler.Behaviors.Responding.Messages.Models.Errors
/// <summary>
/// An internal server error occurred.
/// </summary>
/// <seealso cref="BaseApiStandardResponseBody"/>
/// <seealso cref="BaseSimpleStandardResponseBody"/>
internal sealed class InternalError : BaseSimpleStandardResponseBody
{
/// <summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ internal Detailed(HttpStatusCode httpStatusCode, string processingResult, BaseEn
}

/// <inheritdoc cref="ProcessingFailed"/>
/// <seealso cref="BaseApiStandardResponseBody"/>
internal sealed class Simplified : BaseApiStandardResponseBody
{
/// <summary>
Expand Down
2 changes: 1 addition & 1 deletion EventsHandler/Api/EventsHandler/Constants/DefaultValues.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ internal static class ApiController
{
internal const string Route = "[controller]";

internal const string Version = "1.67";
internal const string Version = "1.68";
}
#endregion

Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,22 @@
// © 2024, Worth Systems.

using Asp.Versioning;
using EventsHandler.Behaviors.Responding.Messages.Models.Base;
using EventsHandler.Constants;
using Microsoft.AspNetCore.Mvc;

namespace EventsHandler.Controllers.Base
{
/// <summary>
/// Parent of all API Controllers in "NotifyNL" OMC.
/// </summary>
[ApiController]
[Route(DefaultValues.ApiController.Route)]
[Consumes(DefaultValues.Request.ContentType)]
[Produces(DefaultValues.Request.ContentType)]
[ApiVersion(DefaultValues.ApiController.Version)]
// Swagger UI
[ProducesResponseType(StatusCodes.Status401Unauthorized, Type = typeof(string))] // REASON: JWT Token is invalid or expired
public abstract class OmcController : Controller
{
private readonly ILogger _logger;
Expand Down
37 changes: 14 additions & 23 deletions EventsHandler/Api/EventsHandler/Controllers/EventsController.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
// © 2023, Worth Systems.

using Asp.Versioning;
using EventsHandler.Attributes.Authorization;
using EventsHandler.Attributes.Validation;
using EventsHandler.Behaviors.Mapping.Enums;
Expand All @@ -16,26 +15,25 @@
using Microsoft.AspNetCore.Mvc;
using Swashbuckle.AspNetCore.Filters;
using System.ComponentModel.DataAnnotations;
using Resources = EventsHandler.Properties.Resources;

namespace EventsHandler.Controllers
{
/// <summary>
/// Controller handling events workflow between "Notificatie API" events queue, services with citizens personal
/// data from the municipalities in The Netherlands ("OpenZaak" and "OpenKlaant"), and "Notify NL" API service.
/// </summary>
/// <seealso cref="Controller"/>
[ApiController]
[Route(DefaultValues.ApiController.Route)]
[Consumes(DefaultValues.Request.ContentType)]
[Produces(DefaultValues.Request.ContentType)]
[ApiVersion(DefaultValues.ApiController.Version)]
/// <seealso cref="OmcController"/>
public sealed class EventsController : OmcController
{
private readonly ISerializationService _serializer;
private readonly IValidationService<NotificationEvent> _validator;
private readonly IProcessingService<NotificationEvent> _processor;
private readonly IRespondingService<NotificationEvent> _responder;

private static readonly (ProcessingResult, string) s_failedResult =
(ProcessingResult.Failure, Resources.Processing_ERROR_Scenario_NotificationNotSent);

/// <summary>
/// Initializes a new instance of the <see cref="EventsController"/> class.
/// </summary>
Expand Down Expand Up @@ -73,7 +71,6 @@ public EventsController(
[ProducesResponseType(StatusCodes.Status202Accepted)] // REASON: The notification was valid, and it was successfully sent to "Notify NL" Web service
[ProducesResponseType(StatusCodes.Status206PartialContent)] // REASON: The notification was not sent (e.g., "test" ping received or scenario is not yet implemented. No need to retry sending it)
[ProducesResponseType(StatusCodes.Status400BadRequest, Type = typeof(ProcessingFailed.Detailed))] // REASON: The notification was not sent (e.g., it was invalid due to missing data or improper structure. Retry sending is required)
[ProducesResponseType(StatusCodes.Status401Unauthorized, Type = typeof(string))] // REASON: JWT Token is invalid or expired
[ProducesResponseType(StatusCodes.Status422UnprocessableEntity, Type = typeof(ProcessingFailed.Detailed))] // REASON: Input deserialization error (e.g. model binding of required properties)
[ProducesResponseType(StatusCodes.Status500InternalServerError, Type = typeof(ProcessingFailed.Detailed))] // REASON: Internal server error (if-else / try-catch-finally handle)
[ProducesResponseType(StatusCodes.Status501NotImplemented, Type = typeof(string))] // REASON: Operation is not implemented (a new case is not yet supported)
Expand All @@ -89,25 +86,19 @@ public async Task<IActionResult> ListenAsync([Required, FromBody] object json)
NotificationEvent notification = this._serializer.Deserialize<NotificationEvent>(json);

// Validation #2: Structural and data inconsistencies of optional properties
HealthCheck healthCheck = this._validator.Validate(ref notification);

if (healthCheck is HealthCheck.OK_Valid
or HealthCheck.OK_Inconsistent)
{
// Process received notification
(ProcessingResult, string) result = await this._processor.ProcessAsync(notification);

return LogAndReturnApiResponse(LogLevel.Information,
this._responder.GetStandardized_Processing_ActionResult(result, notification.Details));
}

return LogAndReturnApiResponse(LogLevel.Error,
this._responder.GetStandardized_Processing_Failed_ActionResult(notification.Details));
return this._validator.Validate(ref notification) is HealthCheck.OK_Valid
or HealthCheck.OK_Inconsistent
// Try to process received notification
? LogAndReturnApiResponse(LogLevel.Information,
this._responder.Get_Processing_Status_ActionResult(await this._processor.ProcessAsync(notification), notification.Details))
// Notification cannot be processed
: LogAndReturnApiResponse(LogLevel.Error,
this._responder.Get_Processing_Status_ActionResult(s_failedResult, notification.Details));
}
catch (Exception exception)
{
return LogAndReturnApiResponse(LogLevel.Critical,
this._responder.GetStandardized_Exception_ActionResult(exception));
this._responder.Get_Exception_ActionResult(exception));
}
}

Expand Down
18 changes: 5 additions & 13 deletions EventsHandler/Api/EventsHandler/Controllers/NotifyController.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
// © 2024, Worth Systems.

using Asp.Versioning;
using EventsHandler.Attributes.Authorization;
using EventsHandler.Attributes.Validation;
using EventsHandler.Behaviors.Communication.Enums;
Expand All @@ -9,7 +8,6 @@
using EventsHandler.Behaviors.Mapping.Models.POCOs.NotificatieApi;
using EventsHandler.Behaviors.Mapping.Models.POCOs.NotifyNL;
using EventsHandler.Behaviors.Responding.Messages.Models.Errors;
using EventsHandler.Constants;
using EventsHandler.Controllers.Base;
using EventsHandler.Extensions;
using EventsHandler.Properties;
Expand All @@ -26,12 +24,7 @@ namespace EventsHandler.Controllers
/// <summary>
/// Controller used to get feedback from "NotifyNL" API web service.
/// </summary>
/// <seealso cref="Controller"/>
[ApiController]
[Route(DefaultValues.ApiController.Route)]
[Consumes(DefaultValues.Request.ContentType)]
[Produces(DefaultValues.Request.ContentType)]
[ApiVersion(DefaultValues.ApiController.Version)]
/// <seealso cref="OmcController"/>
public sealed class NotifyController : OmcController
{
private readonly ISerializationService _serializer;
Expand Down Expand Up @@ -71,7 +64,6 @@ public NotifyController(
[SwaggerRequestExample(typeof(DeliveryReceipt), typeof(DeliveryReceiptExample))] // NOTE: Documentation of expected JSON schema with sample and valid payload values
[ProducesResponseType(StatusCodes.Status202Accepted)] // REASON: The delivery receipt with successful status
[ProducesResponseType(StatusCodes.Status400BadRequest, Type = typeof(ProcessingFailed.Simplified))] // REASON: The delivery receipt with failure status
[ProducesResponseType(StatusCodes.Status401Unauthorized, Type = typeof(string))] // REASON: JWT Token is invalid or expired
[ProducesResponseType(StatusCodes.Status422UnprocessableEntity, Type = typeof(ProcessingFailed.Simplified))] // REASON: The JSON structure is invalid
[ProducesResponseType(StatusCodes.Status500InternalServerError)] // REASON: Internal server error (if-else / try-catch-finally handle)
public async Task<IActionResult> ConfirmAsync([Required, FromBody] object json)
Expand All @@ -89,19 +81,19 @@ DeliveryStatus.TemporaryFailure or
DeliveryStatus.TechnicalFailure))
{
return LogAndReturnApiResponse(LogLevel.Information,
this._responder.GetStandardized_Processing_ActionResult(ProcessingResult.Success, callbackDetails = GetCallbackDetails(callback)));
this._responder.Get_Processing_Status_ActionResult(ProcessingResult.Success, callbackDetails = GetCallbackDetails(callback)));
}

return LogAndReturnApiResponse(LogLevel.Error,
this._responder.GetStandardized_Processing_ActionResult(ProcessingResult.Failure, callbackDetails = GetCallbackDetails(callback)));
this._responder.Get_Processing_Status_ActionResult(ProcessingResult.Failure, callbackDetails = GetCallbackDetails(callback)));
}
catch (Exception exception)
{
// NOTE: If callback.Id == Guid.Empty then to be suspected is exception during DeliveryReceipt deserialization
callbackDetails = GetErrorDetails(callback, exception);

return LogAndReturnApiResponse(LogLevel.Critical,
this._responder.GetStandardized_Exception_ActionResult(exception));
this._responder.Get_Exception_ActionResult(exception));
}
finally
{
Expand Down Expand Up @@ -136,7 +128,7 @@ private async Task ReportAndLogStatusAsync(DeliveryReceipt callback, string call
}
catch (Exception exception)
{
LogApiResponse(LogLevel.Critical, this._responder.GetStandardized_Exception_ActionResult(exception));
LogApiResponse(LogLevel.Critical, this._responder.Get_Exception_ActionResult(exception));
}
}
}
Expand Down
Loading

0 comments on commit 881f6b2

Please sign in to comment.