-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Cart API Introduced and Initial Use Cases (#39)
* added dotnet ShoppingCart project -- for comparisons * used the Eventuous class/record/namespace conventions * forgot to add ItemAddedToCart event * added behavior to state, created identities * removed TODO -- design change * removed the (virtual) solution folder ShoppingCart * introduced barebones of shopping cart API * generated endpoints currently don't support functional command services * generated endpoints currently don't support functional command services * work-around for no cart ID use case (TEMPORARY) * added and removed use cases * added shoppingcart to docker compose (//)
- Loading branch information
1 parent
2f09493
commit 9977081
Showing
23 changed files
with
621 additions
and
17 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS base | ||
USER $APP_UID | ||
WORKDIR /app | ||
EXPOSE 5262 | ||
EXPOSE 5263 | ||
|
||
FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build | ||
ARG BUILD_CONFIGURATION=Release | ||
WORKDIR /src | ||
COPY ["ShoppingCart.Api/ShoppingCart.Api.csproj", "ShoppingCart.Api/"] | ||
COPY ["src/Retail/ShoppingCart/ShoppingCart.csproj", "src/Retail/ShoppingCart/"] | ||
COPY ["src/Core/Ecommerce.Core/Ecommerce.Core.csproj", "src/Core/Ecommerce.Core/"] | ||
COPY ["src/Core/Ecommerce.Eventuous/Ecommerce.Eventuous.csproj", "src/Core/Ecommerce.Eventuous/"] | ||
RUN dotnet restore "ShoppingCart.Api/ShoppingCart.Api.csproj" | ||
COPY . . | ||
WORKDIR "/src/ShoppingCart.Api" | ||
RUN dotnet build "ShoppingCart.Api.csproj" -c $BUILD_CONFIGURATION -o /app/build | ||
|
||
FROM build AS publish | ||
ARG BUILD_CONFIGURATION=Release | ||
RUN dotnet publish "ShoppingCart.Api.csproj" -c $BUILD_CONFIGURATION -o /app/publish /p:UseAppHost=false | ||
|
||
FROM base AS final | ||
WORKDIR /app | ||
COPY --from=publish /app/publish . | ||
ENTRYPOINT ["dotnet", "ShoppingCart.Api.dll"] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
using Eventuous; | ||
using Microsoft.AspNetCore.Mvc; | ||
using static ShoppingCart.CartCommands.V1; | ||
|
||
namespace ShoppingCart.Api.HttpApi; | ||
|
||
[Route("/cart")] | ||
public class CommandApi(IFuncCommandService<CartState> service) : ControllerBase | ||
{ | ||
[HttpPost] | ||
[Route("open")] | ||
public async Task<ActionResult<Result>> OpenCart([FromBody] OpenCart cmd, CancellationToken ct) | ||
{ | ||
var result = await service.Handle(cmd, ct); | ||
return Ok(result); | ||
} | ||
|
||
[HttpPost] | ||
[Route("open-with-id")] | ||
public async Task<ActionResult<Result>> OpenCart([FromBody] OpenCartWithProvidedId cmd, CancellationToken ct) | ||
{ | ||
var result = await service.Handle(cmd, ct); | ||
return Ok(result); | ||
} | ||
|
||
[HttpPost] | ||
[Route("add-product")] | ||
public async Task<ActionResult<Result>> OpenCart([FromBody] AddProductToCart cmd, CancellationToken ct) | ||
{ | ||
var result = await service.Handle(cmd, ct); | ||
return Ok(result); | ||
} | ||
|
||
[HttpPost] | ||
[Route("remove-product")] | ||
public async Task<ActionResult<Result>> OpenCart([FromBody] RemoveProductFromCart cmd, CancellationToken ct) | ||
{ | ||
var result = await service.Handle(cmd, ct); | ||
return Ok(result); | ||
} | ||
|
||
[HttpPost] | ||
[Route("confirm")] | ||
public async Task<ActionResult<Result>> OpenCart([FromBody] ConfirmCart cmd, CancellationToken ct) | ||
{ | ||
var result = await service.Handle(cmd, ct); | ||
return Ok(result); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
using Serilog; | ||
using Serilog.Events; | ||
|
||
namespace ShoppingCart.Api.Infrastructure; | ||
|
||
public static class Logging | ||
{ | ||
public static void ConfigureLog(IConfiguration config) | ||
=> Log.Logger = new LoggerConfiguration() | ||
.MinimumLevel.Verbose() | ||
.MinimumLevel.Override("Microsoft", LogEventLevel.Information) | ||
.MinimumLevel.Override("Microsoft.AspNetCore.Hosting.Diagnostics", LogEventLevel.Warning) | ||
.MinimumLevel.Override("Microsoft.AspNetCore.Mvc.Infrastructure", LogEventLevel.Warning) | ||
.MinimumLevel.Override("Microsoft.AspNetCore.Routing", LogEventLevel.Warning) | ||
.MinimumLevel.Override("Grpc", LogEventLevel.Information) | ||
.MinimumLevel.Override("Grpc.Net.Client.Internal.GrpcCall", LogEventLevel.Error) | ||
.MinimumLevel.Override("EventStore", LogEventLevel.Information) | ||
.Enrich.FromLogContext() | ||
.WriteTo.Console( | ||
outputTemplate: | ||
"[{Timestamp:HH:mm:ss} {Level:u3}] {Message:lj} <s:{SourceContext}>{NewLine}{Exception}" | ||
) | ||
.WriteTo.Seq(config["Seq:ServerUrl"]!) | ||
.CreateLogger(); | ||
} | ||
|
||
public record SeqConfig | ||
{ | ||
public string ServerUrl { get; init; } = null!; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
using Eventuous.Spyglass; | ||
using Microsoft.AspNetCore.Http.Json; | ||
using NodaTime; | ||
using NodaTime.Serialization.SystemTextJson; | ||
using Serilog; | ||
using ShoppingCart.Api; | ||
using ShoppingCart.Api.Infrastructure; | ||
|
||
var builder = WebApplication.CreateBuilder(args); | ||
|
||
Logging.ConfigureLog(builder.Configuration); | ||
builder.Host.UseSerilog(); | ||
|
||
builder.Services | ||
.AddControllers() | ||
.AddJsonOptions(options => | ||
options.JsonSerializerOptions.ConfigureForNodaTime(DateTimeZoneProviders.Tzdb)); | ||
|
||
builder.Services.AddEndpointsApiExplorer(); | ||
builder.Services.AddSwaggerGen(); | ||
builder.Services.AddTelemetry(); | ||
builder.Services.AddEventuous(builder.Configuration); | ||
builder.Services.AddEventuousSpyglass(); | ||
|
||
builder.Services.Configure<JsonOptions>(options => | ||
options.SerializerOptions.ConfigureForNodaTime(DateTimeZoneProviders.Tzdb) | ||
); | ||
|
||
var app = builder.Build(); | ||
|
||
app.UseSwagger(opts => | ||
{ | ||
opts.RouteTemplate = "api/{documentName}/swagger.json"; | ||
}) | ||
.UseSwaggerUI(opts => | ||
{ | ||
opts.SwaggerEndpoint("/api/v1/swagger.json", "ShoppingCart API"); | ||
opts.RoutePrefix = "api"; | ||
}); | ||
app.UseSerilogRequestLogging(); | ||
app.MapControllers(); | ||
app.UseOpenTelemetryPrometheusScrapingEndpoint(); | ||
app.MapEventuousSpyglass(); | ||
|
||
try { | ||
app.Run("http://*:5262"); | ||
return 0; | ||
} | ||
catch (Exception e) { | ||
Log.Fatal(e, "Host terminated unexpectedly"); | ||
return 1; | ||
} | ||
finally { | ||
Log.CloseAndFlush(); | ||
} |
14 changes: 14 additions & 0 deletions
14
src/Retail/ShoppingCart.Api/Properties/launchSettings.json
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
{ | ||
"profiles": { | ||
"http": { | ||
"commandName": "Project", | ||
"dotnetRunMessages": true, | ||
"launchBrowser": true, | ||
"applicationUrl": "http://localhost:5262;https://localhost:5263", | ||
"launchUrl": "api", | ||
"environmentVariables": { | ||
"ASPNETCORE_ENVIRONMENT": "Development" | ||
} | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,80 @@ | ||
using System.Text.Json; | ||
using Ecommerce.Core.Identities; | ||
using Eventuous; | ||
using Eventuous.Diagnostics.OpenTelemetry; | ||
using Eventuous.EventStore; | ||
using Microsoft.Extensions.Diagnostics.HealthChecks; | ||
using OpenTelemetry.Metrics; | ||
using OpenTelemetry.Resources; | ||
using OpenTelemetry.Trace; | ||
|
||
#pragma warning disable CS0618 // Type or member is obsolete | ||
|
||
namespace ShoppingCart.Api; | ||
|
||
public static class Registrations | ||
{ | ||
private const string OTelServiceName = "shoppingcart"; | ||
private const string PostgresSchemaName = "shoppingcart"; | ||
|
||
public static void AddEventuous(this IServiceCollection services, IConfiguration configuration) | ||
{ | ||
DefaultEventSerializer.SetDefaultSerializer( | ||
new DefaultEventSerializer( | ||
new JsonSerializerOptions(JsonSerializerDefaults.Web) | ||
) | ||
); | ||
|
||
// event store (core) | ||
services.AddEventStoreClient(configuration["EventStore:ConnectionString"]!); | ||
services.AddAggregateStore<EsdbEventStore>(); | ||
|
||
// command services (functional services in this module) | ||
services.AddFunctionalService<CartFuncService, CartState>(); | ||
|
||
// other internal and core services | ||
services.AddSingleton<ISnowflakeIdGenerator, SnowflakeIdGenerator>(); | ||
|
||
// health checks for subscription service | ||
services | ||
.AddHealthChecks() | ||
.AddSubscriptionsHealthCheck("subscriptions", HealthStatus.Unhealthy, new []{"tag"}); | ||
} | ||
|
||
public static void AddTelemetry(this IServiceCollection services) | ||
{ | ||
var otelEnabled = Environment.GetEnvironmentVariable("OTEL_EXPORTER_OTLP_ENDPOINT") != null; | ||
|
||
services.AddOpenTelemetry() | ||
.WithMetrics( | ||
builder => | ||
{ | ||
builder | ||
.SetResourceBuilder(ResourceBuilder.CreateDefault().AddService(OTelServiceName)) | ||
.AddAspNetCoreInstrumentation() | ||
.AddEventuous() | ||
.AddEventuousSubscriptions() | ||
.AddPrometheusExporter(); | ||
if (otelEnabled) builder.AddOtlpExporter(); | ||
} | ||
); | ||
|
||
services.AddOpenTelemetry() | ||
.WithTracing( | ||
builder => | ||
{ | ||
builder | ||
.AddAspNetCoreInstrumentation() | ||
.AddGrpcClientInstrumentation() | ||
.AddEventuousTracing() | ||
.SetResourceBuilder(ResourceBuilder.CreateDefault().AddService(OTelServiceName)) | ||
.SetSampler(new AlwaysOnSampler()); | ||
|
||
if (otelEnabled) | ||
builder.AddOtlpExporter(); | ||
else | ||
builder.AddZipkinExporter(); | ||
} | ||
); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
<Project Sdk="Microsoft.NET.Sdk.Web"> | ||
|
||
<PropertyGroup> | ||
<DockerDefaultTargetOS>Linux</DockerDefaultTargetOS> | ||
</PropertyGroup> | ||
|
||
<ItemGroup> | ||
<PackageReference Include="Eventuous.Diagnostics.OpenTelemetry" Version="$(EventuousVersion)" /> | ||
<PackageReference Include="Eventuous.Application" Version="$(EventuousVersion)" /> | ||
<PackageReference Include="Eventuous.EventStore" Version="$(EventuousVersion)" /> | ||
<PackageReference Include="Eventuous.AspNetCore.Web" Version="$(EventuousVersion)" /> | ||
<PackageReference Include="Eventuous.Spyglass" Version="$(EventuousVersion)" /> | ||
<PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="8.0.6" /> | ||
<PackageReference Include="NodaTime.Serialization.SystemTextJson" Version="1.2.0" /> | ||
<PackageReference Include="OpenTelemetry.Exporter.Prometheus.AspNetCore" Version="1.4.0-rc.4" /> | ||
<PackageReference Include="OpenTelemetry.Exporter.Zipkin" Version="1.9.0" /> | ||
<PackageReference Include="OpenTelemetry.Exporter.OpenTelemetryProtocol" Version="1.9.0" /> | ||
<PackageReference Include="OpenTelemetry.Instrumentation.AspNetCore" Version="1.8.1" /> | ||
<PackageReference Include="OpenTelemetry.Instrumentation.GrpcNetClient" Version="1.0.0-rc9.14" /> | ||
<PackageReference Include="Serilog.AspNetCore" Version="8.0.1" /> | ||
<PackageReference Include="Serilog.Sinks.Console" Version="6.0.0" /> | ||
<PackageReference Include="Serilog.Sinks.Seq" Version="8.0.0" /> | ||
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.6.2" /> | ||
</ItemGroup> | ||
|
||
<ItemGroup> | ||
<ProjectReference Include="..\..\Core\Ecommerce.Core.WebApi\Ecommerce.Core.WebApi.csproj" /> | ||
<ProjectReference Include="..\ShoppingCart\ShoppingCart.csproj" /> | ||
</ItemGroup> | ||
|
||
<ItemGroup> | ||
<Content Include="..\.dockerignore"> | ||
<Link>.dockerignore</Link> | ||
</Content> | ||
</ItemGroup> | ||
|
||
</Project> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
@ShoppingCart.Api_HostAddress = http://localhost:5146 | ||
|
||
GET {{ShoppingCart.Api_HostAddress}}/weatherforecast/ | ||
Accept: application/json | ||
|
||
### |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
{ | ||
"Logging": { | ||
"LogLevel": { | ||
"Default": "Information", | ||
"Microsoft": "Warning", | ||
"Microsoft.Hosting.Lifetime": "Information" | ||
} | ||
}, | ||
"Seq": { | ||
"ServerUrl": "http://localhost:5341" | ||
}, | ||
"EventStore": { | ||
"ConnectionString": "esdb://localhost:2113?tls=false" | ||
} | ||
} |
Oops, something went wrong.