Skip to content
Draft

wip #829

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions src/Basket.API/Basket.API.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@
<ItemGroup>
<PackageReference Include="Aspire.StackExchange.Redis" />
<PackageReference Include="Grpc.AspNetCore" />
<PackageReference Include="Grpc.Tools">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
</ItemGroup>

<ItemGroup>
Expand Down
9 changes: 6 additions & 3 deletions src/Basket.API/Grpc/BasketService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,8 @@ public override async Task<CustomerBasketResponse> GetBasket(GetBasketRequest re
logger.LogDebug("Begin GetBasketById call from method {Method} for basket id {Id}", context.Method, userId);
}

var data = await repository.GetBasketAsync(userId);
var basketId = request.BasketId; // Extract basketId from the request
var data = await repository.GetBasketAsync(userId, basketId); // Pass both userId and basketId

if (data is not null)
{
Expand All @@ -47,7 +48,7 @@ public override async Task<CustomerBasketResponse> UpdateBasket(UpdateBasketRequ
}

var customerBasket = MapToCustomerBasket(userId, request);
var response = await repository.UpdateBasketAsync(customerBasket);
var response = await repository.UpdateBasketAsync(userId, customerBasket);
if (response is null)
{
ThrowBasketDoesNotExist(userId);
Expand All @@ -64,7 +65,9 @@ public override async Task<DeleteBasketResponse> DeleteBasket(DeleteBasketReques
ThrowNotAuthenticated();
}

await repository.DeleteBasketAsync(userId);
var basketId = request.BasketId;
await repository.DeleteBasketAsync(userId, basketId);

return new();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,6 @@ public async Task Handle(OrderStartedIntegrationEvent @event)
{
logger.LogInformation("Handling integration event: {IntegrationEventId} - ({@IntegrationEvent})", @event.Id, @event);

await repository.DeleteBasketAsync(@event.UserId);
await repository.DeleteBasketAsync(@event.UserId, @event.BasketId);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,4 @@
// Integration Events notes:
// An Event is "something that has happened in the past", therefore its name has to be
// An Integration Event is an event that can cause side effects to other microservices, Bounded-Contexts or external systems.
public record OrderStartedIntegrationEvent(string UserId) : IntegrationEvent;
public record OrderStartedIntegrationEvent(string UserId, string BasketId) : IntegrationEvent;
2 changes: 2 additions & 0 deletions src/Basket.API/Model/CustomerBasket.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

public class CustomerBasket
{
public string Id { get; set; }

public string BuyerId { get; set; }

public List<BasketItem> Items { get; set; } = [];
Expand Down
18 changes: 18 additions & 0 deletions src/Basket.API/Proto/basket.proto
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,12 @@ service Basket {
rpc GetBasket(GetBasketRequest) returns (CustomerBasketResponse) {}
rpc UpdateBasket(UpdateBasketRequest) returns (CustomerBasketResponse) {}
rpc DeleteBasket(DeleteBasketRequest) returns (DeleteBasketResponse) {}
rpc CreateBasket(CreateBasketRequest) returns (CreateBasketResponse) {}
rpc ListBaskets(ListBasketRequest) returns (ListBasketResponse) {}
}

message GetBasketRequest {
string basket_id = 1;
}

message CustomerBasketResponse {
Expand All @@ -22,12 +25,27 @@ message BasketItem {
int32 quantity = 6;
}

message ListBasketRequest {
}

message ListBasketResponse {
repeated string basket_ids = 1;
}

message UpdateBasketRequest {
repeated BasketItem items = 2;
}

message DeleteBasketRequest {
string basket_id = 1;
}

message DeleteBasketResponse {
}

message CreateBasketRequest {
}

message CreateBasketResponse {
string basket_id = 1;
}
8 changes: 5 additions & 3 deletions src/Basket.API/Repositories/IBasketRepository.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@ namespace eShop.Basket.API.Repositories;

public interface IBasketRepository
{
Task<CustomerBasket> GetBasketAsync(string customerId);
Task<CustomerBasket> UpdateBasketAsync(CustomerBasket basket);
Task<bool> DeleteBasketAsync(string id);
Task<CustomerBasket> GetBasketAsync(string customerId, string basketId);
Task<CustomerBasket> UpdateBasketAsync(string customerId, CustomerBasket basket);
Task<bool> DeleteBasketAsync(string customerId, string basketId);
Task<CustomerBasket> CreateBasketAsync(string customerId);
Task<IReadOnlyList<CustomerBasket>> ListBasketsAsync(string customerId);
}
18 changes: 8 additions & 10 deletions src/Basket.API/Repositories/RedisBasketRepository.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,16 +13,15 @@ public class RedisBasketRepository(ILogger<RedisBasketRepository> logger, IConne
private static RedisKey BasketKeyPrefix = "/basket/"u8.ToArray();
// note on UTF8 here: library limitation (to be fixed) - prefixes are more efficient as blobs

private static RedisKey GetBasketKey(string userId) => BasketKeyPrefix.Append(userId);

public async Task<bool> DeleteBasketAsync(string id)
private static RedisKey GetBasketKey(string userId, string basketId) => BasketKeyPrefix.Append(userId).Append(basketId);
public async Task<bool> DeleteBasketAsync(string userId, string basketId)
{
return await _database.KeyDeleteAsync(GetBasketKey(id));
return await _database.KeyDeleteAsync(GetBasketKey(userId, basketId));
}

public async Task<CustomerBasket> GetBasketAsync(string customerId)
public async Task<CustomerBasket> GetBasketAsync(string userId, string basketId)
{
using var data = await _database.StringGetLeaseAsync(GetBasketKey(customerId));
using var data = await _database.StringGetLeaseAsync(GetBasketKey(userId, basketId));

if (data is null || data.Length == 0)
{
Expand All @@ -31,20 +30,19 @@ public async Task<CustomerBasket> GetBasketAsync(string customerId)
return JsonSerializer.Deserialize(data.Span, BasketSerializationContext.Default.CustomerBasket);
}

public async Task<CustomerBasket> UpdateBasketAsync(CustomerBasket basket)
public async Task<CustomerBasket> UpdateBasketAsync(string userId, CustomerBasket basket)
{
var json = JsonSerializer.SerializeToUtf8Bytes(basket, BasketSerializationContext.Default.CustomerBasket);
var created = await _database.StringSetAsync(GetBasketKey(basket.BuyerId), json);
var created = await _database.StringSetAsync(GetBasketKey(userId, basket.Id), json);

if (!created)
{
logger.LogInformation("Problem occurred persisting the item.");
return null;
}


logger.LogInformation("Basket item persisted successfully.");
return await GetBasketAsync(basket.BuyerId);
return await GetBasketAsync(userId, basket.Id);
}
}

Expand Down