Newer
Older
OptimisticConcurrency / eventstore / Program.cs
@Derek Comartin Derek Comartin on 10 Nov 2021 2 KB Init
using EventSourcing.Demo;
using EventStore.ClientAPI.Exceptions;
using Microsoft.AspNetCore.Mvc;

var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();

app.MapGet("/products/{sku}", async (HttpResponse response, string sku) =>
{
    using var stream = await WarehouseProductEventStoreStream.Factory();
    var product = await stream.Get(sku);
    //response.Headers.ETag = product.Version.ToString();

    return new
    {
        Sku = product.Aggregate.Sku,
        Quantity = product.Aggregate.GetQuantityOnHand(),
        Version = product.Version,
        Commands = new Command[]
        {
            new("InventoryAdjustment", $"/products/{sku}/{product.Version}/adjustment")
        }
    };
});

app.MapPost("/products/{sku}/adjustment", async (HttpRequest request, HttpResponse response, [FromRoute]string sku, [FromBody]InventoryAdjustment inventoryAdjustment) =>
{
    using var stream = await WarehouseProductEventStoreStream.Factory();
    var product = await stream.Get(sku);
    product.Aggregate.AdjustInventory(inventoryAdjustment.Quantity, inventoryAdjustment.Reason);

    var eTag = request.GetIfMatch();
    if (eTag != null)
    {
        try
        {
            await stream.Save(product.Aggregate, eTag.Value);
            response.StatusCode = 204;
            return;
        }
        catch (WrongExpectedVersionException)
        {
            response.StatusCode = 412;
        }
    }

    response.StatusCode = 412;
});

app.MapPost("/products/{sku}/{version}/adjustment",
    async (HttpResponse response, [FromRoute]string sku, [FromRoute]long version, [FromBody]InventoryAdjustment inventoryAdjustment) =>
{
    using var stream = await WarehouseProductEventStoreStream.Factory();
    var product = await stream.Get(sku);
    product.Aggregate.AdjustInventory(inventoryAdjustment.Quantity, inventoryAdjustment.Reason);
    try
    {
        await stream.Save(product.Aggregate, version);
    }
    catch (WrongExpectedVersionException)
    {
        response.StatusCode = 412;
    }
});

app.Run();

public class InventoryAdjustment
{
    public int Quantity { get; set; }
    public string Reason { get; set; }
}

public static class Extensions
{
    public static long? GetIfMatch(this HttpRequest request)
    {
        var headers = request.GetTypedHeaders();
        var eTag = headers.IfMatch.FirstOrDefault()?.Tag.Value.Replace("\"", "");
        if (eTag != null && long.TryParse(eTag, out var version))
        {
            return version;
        }

        return null;
    }
}

public class Command
{
    public Command(string action, string uri)
    {
        Action = action;
        Uri = uri;
    }

    public string Action { get; set; }
    public string Uri { get; set; }
}