diff --git a/Boundaries/Comanda.Orchestrator/Source/Comanda.Orchestrator.WebApi/Comanda.Orchestrator.WebApi.csproj b/Boundaries/Comanda.Orchestrator/Source/Comanda.Orchestrator.WebApi/Comanda.Orchestrator.WebApi.csproj index ac7827f..6431dc7 100644 --- a/Boundaries/Comanda.Orchestrator/Source/Comanda.Orchestrator.WebApi/Comanda.Orchestrator.WebApi.csproj +++ b/Boundaries/Comanda.Orchestrator/Source/Comanda.Orchestrator.WebApi/Comanda.Orchestrator.WebApi.csproj @@ -13,6 +13,7 @@ + diff --git a/Boundaries/Comanda.Orchestrator/Source/Comanda.Orchestrator.WebApi/Controllers/OrdersController.cs b/Boundaries/Comanda.Orchestrator/Source/Comanda.Orchestrator.WebApi/Controllers/OrdersController.cs index 371e163..c0632ce 100644 --- a/Boundaries/Comanda.Orchestrator/Source/Comanda.Orchestrator.WebApi/Controllers/OrdersController.cs +++ b/Boundaries/Comanda.Orchestrator/Source/Comanda.Orchestrator.WebApi/Controllers/OrdersController.cs @@ -32,6 +32,7 @@ public async Task GetOrdersAsync([FromQuery] OrdersFetchParameter } [HttpPost] + [Idempotent] // https://developer.mozilla.org/en-US/docs/Glossary/Idempotent [Authorize(Roles = Permissions.CreateOrder)] public async Task CreateOrderAsync([FromBody] OrderCreationScheme request, CancellationToken cancellation) { diff --git a/Boundaries/Comanda.Orchestrator/Source/Comanda.Orchestrator.WebApi/Controllers/PaymentsController.cs b/Boundaries/Comanda.Orchestrator/Source/Comanda.Orchestrator.WebApi/Controllers/PaymentsController.cs index 9468ac0..0d60b34 100644 --- a/Boundaries/Comanda.Orchestrator/Source/Comanda.Orchestrator.WebApi/Controllers/PaymentsController.cs +++ b/Boundaries/Comanda.Orchestrator/Source/Comanda.Orchestrator.WebApi/Controllers/PaymentsController.cs @@ -7,6 +7,7 @@ public sealed class PaymentsController(IDispatcher dispatcher, IEventDispatcher eventDispatcher) : ControllerBase { [HttpPost("online")] + [Idempotent] // https://developer.mozilla.org/en-US/docs/Glossary/Idempotent [Authorize(Roles = Permissions.MakePayment)] public async Task CreateOnlineChargeAsync( [FromBody] CheckoutSessionCreationScheme request, [FromHeader(Name = Headers.Credential)] string credential, CancellationToken cancellation) @@ -33,6 +34,7 @@ public async Task CreateOnlineChargeAsync( } [HttpPost("offline")] + [Idempotent] // https://developer.mozilla.org/en-US/docs/Glossary/Idempotent [Authorize(Roles = Permissions.MakePayment)] public async Task CreateOfflinePaymentAsync([FromBody] OfflinePaymentScheme request, CancellationToken cancellation) { diff --git a/Boundaries/Comanda.Orchestrator/Source/Comanda.Orchestrator.WebApi/Controllers/ProfilesController.cs b/Boundaries/Comanda.Orchestrator/Source/Comanda.Orchestrator.WebApi/Controllers/ProfilesController.cs index 740477d..8fd8bbb 100644 --- a/Boundaries/Comanda.Orchestrator/Source/Comanda.Orchestrator.WebApi/Controllers/ProfilesController.cs +++ b/Boundaries/Comanda.Orchestrator/Source/Comanda.Orchestrator.WebApi/Controllers/ProfilesController.cs @@ -32,6 +32,7 @@ public async Task GetCustomersAsync([FromQuery] FetchCustomersPar } [HttpPost("customers")] + [Idempotent] // https://developer.mozilla.org/en-US/docs/Glossary/Idempotent [Authorize] public async Task CreateCustomerAsync([FromBody] CustomerCreationScheme request, CancellationToken cancellation) { @@ -138,6 +139,7 @@ public async Task GetCustomerAddressesAsync( [HttpPost("customers/{customerId}/addresses")] [Authorize(Roles = Permissions.EditCustomers)] + [Idempotent] public async Task AssignCustomerAddressAsync( [FromBody] AssignCustomerAddressScheme request, [FromRoute] string customerId, CancellationToken cancellation) { @@ -232,6 +234,7 @@ public async Task GetOwnersAsync([FromQuery] FetchOwnersParameter } [HttpPost("owners")] + [Idempotent] // https://developer.mozilla.org/en-US/docs/Glossary/Idempotent [Authorize] public async Task CreateOwnerAsync([FromBody] OwnerCreationScheme request, CancellationToken cancellation) { diff --git a/Boundaries/Comanda.Orchestrator/Source/Comanda.Orchestrator.WebApi/Controllers/StoresController.cs b/Boundaries/Comanda.Orchestrator/Source/Comanda.Orchestrator.WebApi/Controllers/StoresController.cs index 87d5558..fb7fbde 100644 --- a/Boundaries/Comanda.Orchestrator/Source/Comanda.Orchestrator.WebApi/Controllers/StoresController.cs +++ b/Boundaries/Comanda.Orchestrator/Source/Comanda.Orchestrator.WebApi/Controllers/StoresController.cs @@ -35,6 +35,7 @@ public async Task GetEstablishmentsAsync( } [HttpPost] + [Idempotent] // https://developer.mozilla.org/en-US/docs/Glossary/Idempotent [Authorize(Roles = Permissions.CreateEstablishment)] public async Task CreateEstablishmentAsync( [FromBody] EstablishmentCreationScheme request, CancellationToken cancellation) @@ -111,6 +112,7 @@ public async Task DeleteEstablishmentAsync( [HttpPost("{establishmentId}/checkout")] [Authorize(Roles = Permissions.MakePayment)] + [Idempotent] // https://developer.mozilla.org/en-US/docs/Glossary/Idempotent public async Task CheckoutAsync( [FromBody] CreateCheckoutScheme request, [FromRoute] string establishmentId, CancellationToken cancellation) { @@ -162,6 +164,7 @@ public async Task GetProductsAsync( [HttpPost("{establishmentId}/products")] [Authorize(Roles = Permissions.CreateProduct)] + [Idempotent] // https://developer.mozilla.org/en-US/docs/Glossary/Idempotent public async Task CreateProductAsync( [FromBody] ProductCreationScheme request, [FromRoute] string establishmentId, CancellationToken cancellation) { @@ -292,6 +295,7 @@ public async Task GetCredentialsAsync( [HttpPost("{establishmentId}/integrations/credentials")] [Authorize(Roles = Permissions.CreateCredential)] + [Idempotent] // https://developer.mozilla.org/en-US/docs/Glossary/Idempotent public async Task AssignCredentialAsync( [FromBody] CredentialCreationScheme request, [FromRoute] string establishmentId, CancellationToken cancellation) { diff --git a/Boundaries/Comanda.Orchestrator/Source/Comanda.Orchestrator.WebApi/Controllers/SubscriptionsController.cs b/Boundaries/Comanda.Orchestrator/Source/Comanda.Orchestrator.WebApi/Controllers/SubscriptionsController.cs index eb026df..114942d 100644 --- a/Boundaries/Comanda.Orchestrator/Source/Comanda.Orchestrator.WebApi/Controllers/SubscriptionsController.cs +++ b/Boundaries/Comanda.Orchestrator/Source/Comanda.Orchestrator.WebApi/Controllers/SubscriptionsController.cs @@ -6,6 +6,7 @@ public sealed class SubscriptionsController(IDispatcher dispatcher) : Controller { [HttpPost] [Authorize(Roles = Permissions.Subscribe)] + [Idempotent] // https://developer.mozilla.org/en-US/docs/Glossary/Idempotent public async Task CreateCheckoutSessionAsync( [FromBody] SubscriptionCheckoutSessionCreationScheme request, CancellationToken cancellation) { @@ -29,6 +30,7 @@ public async Task CreateCheckoutSessionAsync( [HttpDelete("{id}")] [Authorize(Roles = Permissions.CancelSubscription)] + [Idempotent] // https://developer.mozilla.org/en-US/docs/Glossary/Idempotent public async Task CancelSubscriptionAsync( [FromQuery] SubscriptionCancelationScheme request, [FromRoute] string id, CancellationToken cancellation) { diff --git a/Boundaries/Comanda.Orchestrator/Source/Comanda.Orchestrator.WebApi/Extensions/WebInfrastructureExtension.cs b/Boundaries/Comanda.Orchestrator/Source/Comanda.Orchestrator.WebApi/Extensions/WebInfrastructureExtension.cs index dff9168..0e5657e 100644 --- a/Boundaries/Comanda.Orchestrator/Source/Comanda.Orchestrator.WebApi/Extensions/WebInfrastructureExtension.cs +++ b/Boundaries/Comanda.Orchestrator/Source/Comanda.Orchestrator.WebApi/Extensions/WebInfrastructureExtension.cs @@ -27,5 +27,13 @@ public static void AddWebComposition(this IServiceCollection services) options.Realm = settings.Federation.Realm; options.ClientSecret = settings.Federation.ClientSecret; }); + + services.AddIdempotency() + .WithInMemoryCache(options => + { + options.DefaultCacheExpiration = TimeSpan.FromMinutes(1); + options.DefaultHeaderName = Headers.Idempotency; + options.ThrowOnMissingKey = false; + }); } } diff --git a/Boundaries/Comanda.Orchestrator/Source/Comanda.Orchestrator.WebApi/Usings.cs b/Boundaries/Comanda.Orchestrator/Source/Comanda.Orchestrator.WebApi/Usings.cs index 11ce87d..02b9c73 100644 --- a/Boundaries/Comanda.Orchestrator/Source/Comanda.Orchestrator.WebApi/Usings.cs +++ b/Boundaries/Comanda.Orchestrator/Source/Comanda.Orchestrator.WebApi/Usings.cs @@ -37,8 +37,11 @@ global using HttpsRichardy.Federation.Sdk.Extensions; global using HttpsRichardy.Federation.Sdk.Contracts.Errors; -global using Scalar.AspNetCore; global using Serilog; global using Serilog.Context; + +global using Scalar.AspNetCore; global using FluentValidation.AspNetCore; +global using Idempwanna.Core.Configuration; +global using Idempwanna.Core.Attributes;