feat(furniture-bff): integrate service contract edge adapters
This commit is contained in:
parent
0c79368eb6
commit
97324b367a
@ -11,5 +11,6 @@
|
|||||||
## Edge Responsibilities
|
## Edge Responsibilities
|
||||||
|
|
||||||
- Validate and normalize consumer request inputs.
|
- Validate and normalize consumer request inputs.
|
||||||
- Map downstream service responses to consumer-facing shapes.
|
- Map edge requests to furniture-service transport-neutral contracts.
|
||||||
|
- Map downstream furniture-service responses to consumer-facing shapes.
|
||||||
- Map downstream errors to consistent API error models.
|
- Map downstream errors to consistent API error models.
|
||||||
|
|||||||
@ -5,9 +5,14 @@ package "furniture-bff" {
|
|||||||
class Program
|
class Program
|
||||||
interface IGetFurnitureAvailabilityHandler
|
interface IGetFurnitureAvailabilityHandler
|
||||||
class GetFurnitureAvailabilityHandler
|
class GetFurnitureAvailabilityHandler
|
||||||
|
interface IFurnitureAvailabilityEdgeContractAdapter
|
||||||
|
interface IFurnitureAvailabilityEdgeGrpcContractAdapter
|
||||||
|
class GetFurnitureAvailabilityEdgeGrpcContract
|
||||||
interface IFurnitureServiceClient
|
interface IFurnitureServiceClient
|
||||||
|
|
||||||
GetFurnitureAvailabilityHandler ..|> IGetFurnitureAvailabilityHandler
|
GetFurnitureAvailabilityHandler ..|> IGetFurnitureAvailabilityHandler
|
||||||
|
GetFurnitureAvailabilityHandler --> IFurnitureAvailabilityEdgeContractAdapter
|
||||||
|
IFurnitureAvailabilityEdgeGrpcContractAdapter --> GetFurnitureAvailabilityEdgeGrpcContract
|
||||||
GetFurnitureAvailabilityHandler --> IFurnitureServiceClient
|
GetFurnitureAvailabilityHandler --> IFurnitureServiceClient
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -16,5 +21,5 @@ package "furniture-service" as FurnitureService
|
|||||||
|
|
||||||
Consumers --> Program : REST
|
Consumers --> Program : REST
|
||||||
Program --> IGetFurnitureAvailabilityHandler
|
Program --> IGetFurnitureAvailabilityHandler
|
||||||
IFurnitureServiceClient ..> FurnitureService : gRPC/internal
|
IFurnitureServiceClient ..> FurnitureService : service contracts
|
||||||
@enduml
|
@enduml
|
||||||
|
|||||||
@ -9,6 +9,7 @@
|
|||||||
|
|
||||||
- Preserve correlation headers to downstream service calls.
|
- Preserve correlation headers to downstream service calls.
|
||||||
- Add correlation headers if missing at the edge.
|
- Add correlation headers if missing at the edge.
|
||||||
|
- Populate furniture-service request contracts with correlation identifiers.
|
||||||
|
|
||||||
## Observability Baseline
|
## Observability Baseline
|
||||||
|
|
||||||
|
|||||||
@ -0,0 +1,24 @@
|
|||||||
|
using Furniture.Bff.Contracts.Api;
|
||||||
|
using Furniture.Service.Contracts.UseCases;
|
||||||
|
|
||||||
|
namespace Furniture.Bff.Application.Adapters;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Defines adapter boundary between furniture BFF edge contracts and furniture service contracts.
|
||||||
|
/// </summary>
|
||||||
|
public interface IFurnitureAvailabilityEdgeContractAdapter
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Maps edge API request into furniture service request contract.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="request">Edge API request.</param>
|
||||||
|
/// <returns>Furniture service request contract.</returns>
|
||||||
|
GetFurnitureAvailabilityRequest ToServiceRequest(GetFurnitureAvailabilityApiRequest request);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Maps furniture service response contract into edge API response.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="response">Furniture service response contract.</param>
|
||||||
|
/// <returns>Edge API response.</returns>
|
||||||
|
GetFurnitureAvailabilityApiResponse ToApiResponse(GetFurnitureAvailabilityResponse response);
|
||||||
|
}
|
||||||
@ -0,0 +1,24 @@
|
|||||||
|
using Furniture.Bff.Application.Grpc;
|
||||||
|
using Furniture.Bff.Contracts.Api;
|
||||||
|
|
||||||
|
namespace Furniture.Bff.Application.Adapters;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Defines adapter boundary for gRPC translation at the furniture edge.
|
||||||
|
/// </summary>
|
||||||
|
public interface IFurnitureAvailabilityEdgeGrpcContractAdapter
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Maps edge API request into gRPC contract shape.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="request">Edge API request.</param>
|
||||||
|
/// <returns>gRPC request contract shape.</returns>
|
||||||
|
GetFurnitureAvailabilityEdgeGrpcContract ToGrpc(GetFurnitureAvailabilityApiRequest request);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Maps gRPC request contract shape back into edge API request.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="contract">gRPC request contract shape.</param>
|
||||||
|
/// <returns>Edge API request.</returns>
|
||||||
|
GetFurnitureAvailabilityApiRequest FromGrpc(GetFurnitureAvailabilityEdgeGrpcContract contract);
|
||||||
|
}
|
||||||
@ -1,4 +1,4 @@
|
|||||||
using Furniture.Bff.Contracts.Api;
|
using Furniture.Service.Contracts.UseCases;
|
||||||
|
|
||||||
namespace Furniture.Bff.Application.Adapters;
|
namespace Furniture.Bff.Application.Adapters;
|
||||||
|
|
||||||
@ -10,7 +10,7 @@ public interface IFurnitureServiceClient
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Retrieves furniture availability from downstream service.
|
/// Retrieves furniture availability from downstream service.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="furnitureId">Furniture identifier.</param>
|
/// <param name="request">Service-layer availability request contract.</param>
|
||||||
/// <returns>Consumer-ready availability contract.</returns>
|
/// <returns>Service-layer availability response contract.</returns>
|
||||||
Task<GetFurnitureAvailabilityApiResponse> GetAvailabilityAsync(string furnitureId);
|
Task<GetFurnitureAvailabilityResponse> GetAvailabilityAsync(GetFurnitureAvailabilityRequest request);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -6,5 +6,6 @@
|
|||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\Furniture.Bff.Contracts\Furniture.Bff.Contracts.csproj" />
|
<ProjectReference Include="..\Furniture.Bff.Contracts\Furniture.Bff.Contracts.csproj" />
|
||||||
|
<ProjectReference Include="..\..\..\furniture-service\src\Furniture.Service.Contracts\Furniture.Service.Contracts.csproj" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
||||||
|
|||||||
@ -0,0 +1,8 @@
|
|||||||
|
namespace Furniture.Bff.Application.Grpc;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Defines minimal gRPC contract shape for furniture availability edge translation.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="FurnitureId">Furniture identifier provided by consumers.</param>
|
||||||
|
/// <param name="CorrelationId">Request correlation identifier.</param>
|
||||||
|
public sealed record GetFurnitureAvailabilityEdgeGrpcContract(string FurnitureId, string CorrelationId);
|
||||||
@ -6,12 +6,16 @@ namespace Furniture.Bff.Application.Handlers;
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Default edge handler implementation for furniture availability.
|
/// Default edge handler implementation for furniture availability.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public sealed class GetFurnitureAvailabilityHandler(IFurnitureServiceClient serviceClient)
|
public sealed class GetFurnitureAvailabilityHandler(
|
||||||
|
IFurnitureServiceClient serviceClient,
|
||||||
|
IFurnitureAvailabilityEdgeContractAdapter contractAdapter)
|
||||||
: IGetFurnitureAvailabilityHandler
|
: IGetFurnitureAvailabilityHandler
|
||||||
{
|
{
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public Task<GetFurnitureAvailabilityApiResponse> HandleAsync(GetFurnitureAvailabilityApiRequest request)
|
public async Task<GetFurnitureAvailabilityApiResponse> HandleAsync(GetFurnitureAvailabilityApiRequest request)
|
||||||
{
|
{
|
||||||
return serviceClient.GetAvailabilityAsync(request.FurnitureId);
|
var serviceRequest = contractAdapter.ToServiceRequest(request);
|
||||||
|
var serviceResponse = await serviceClient.GetAvailabilityAsync(serviceRequest);
|
||||||
|
return contractAdapter.ToApiResponse(serviceResponse);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -4,4 +4,5 @@ namespace Furniture.Bff.Contracts.Api;
|
|||||||
/// External REST request contract for furniture availability.
|
/// External REST request contract for furniture availability.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="FurnitureId">Furniture identifier provided by consumers.</param>
|
/// <param name="FurnitureId">Furniture identifier provided by consumers.</param>
|
||||||
public sealed record GetFurnitureAvailabilityApiRequest(string FurnitureId);
|
/// <param name="CorrelationId">Cross-service correlation identifier.</param>
|
||||||
|
public sealed record GetFurnitureAvailabilityApiRequest(string FurnitureId, string CorrelationId = "");
|
||||||
|
|||||||
@ -4,5 +4,6 @@ namespace Furniture.Bff.Contracts.Api;
|
|||||||
/// External REST response contract for furniture availability.
|
/// External REST response contract for furniture availability.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="FurnitureId">Requested furniture identifier.</param>
|
/// <param name="FurnitureId">Requested furniture identifier.</param>
|
||||||
|
/// <param name="DisplayName">Display name to present to consumer clients.</param>
|
||||||
/// <param name="QuantityAvailable">Availability value for client display.</param>
|
/// <param name="QuantityAvailable">Availability value for client display.</param>
|
||||||
public sealed record GetFurnitureAvailabilityApiResponse(string FurnitureId, int QuantityAvailable);
|
public sealed record GetFurnitureAvailabilityApiResponse(string FurnitureId, string DisplayName, int QuantityAvailable);
|
||||||
|
|||||||
@ -0,0 +1,25 @@
|
|||||||
|
using Furniture.Bff.Contracts.Api;
|
||||||
|
|
||||||
|
namespace Furniture.Bff.Application.UnitTests;
|
||||||
|
|
||||||
|
public class ContractShapeTests
|
||||||
|
{
|
||||||
|
[Fact]
|
||||||
|
public void GetFurnitureAvailabilityApiRequest_WhenCreated_StoresCorrelationId()
|
||||||
|
{
|
||||||
|
var request = new GetFurnitureAvailabilityApiRequest("FUR-001", "corr-123");
|
||||||
|
|
||||||
|
Assert.Equal("FUR-001", request.FurnitureId);
|
||||||
|
Assert.Equal("corr-123", request.CorrelationId);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void GetFurnitureAvailabilityApiResponse_WhenCreated_StoresDisplayName()
|
||||||
|
{
|
||||||
|
var response = new GetFurnitureAvailabilityApiResponse("FUR-001", "Chair", 8);
|
||||||
|
|
||||||
|
Assert.Equal("FUR-001", response.FurnitureId);
|
||||||
|
Assert.Equal("Chair", response.DisplayName);
|
||||||
|
Assert.Equal(8, response.QuantityAvailable);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,6 +1,7 @@
|
|||||||
using Furniture.Bff.Application.Adapters;
|
using Furniture.Bff.Application.Adapters;
|
||||||
using Furniture.Bff.Application.Handlers;
|
using Furniture.Bff.Application.Handlers;
|
||||||
using Furniture.Bff.Contracts.Api;
|
using Furniture.Bff.Contracts.Api;
|
||||||
|
using Furniture.Service.Contracts.UseCases;
|
||||||
|
|
||||||
namespace Furniture.Bff.Application.UnitTests;
|
namespace Furniture.Bff.Application.UnitTests;
|
||||||
|
|
||||||
@ -9,19 +10,38 @@ public class GetFurnitureAvailabilityHandlerTests
|
|||||||
[Fact]
|
[Fact]
|
||||||
public async Task HandleAsync_WhenCalled_DelegatesToServiceClient()
|
public async Task HandleAsync_WhenCalled_DelegatesToServiceClient()
|
||||||
{
|
{
|
||||||
var handler = new GetFurnitureAvailabilityHandler(new FakeFurnitureServiceClient());
|
var handler = new GetFurnitureAvailabilityHandler(
|
||||||
|
new FakeFurnitureServiceClient(),
|
||||||
|
new FakeFurnitureAvailabilityEdgeContractAdapter());
|
||||||
|
|
||||||
var response = await handler.HandleAsync(new GetFurnitureAvailabilityApiRequest("FUR-001"));
|
var response = await handler.HandleAsync(new GetFurnitureAvailabilityApiRequest("FUR-001", "corr-123"));
|
||||||
|
|
||||||
Assert.Equal("FUR-001", response.FurnitureId);
|
Assert.Equal("FUR-001", response.FurnitureId);
|
||||||
|
Assert.Equal("Chair", response.DisplayName);
|
||||||
Assert.Equal(3, response.QuantityAvailable);
|
Assert.Equal(3, response.QuantityAvailable);
|
||||||
}
|
}
|
||||||
|
|
||||||
private sealed class FakeFurnitureServiceClient : IFurnitureServiceClient
|
private sealed class FakeFurnitureServiceClient : IFurnitureServiceClient
|
||||||
{
|
{
|
||||||
public Task<GetFurnitureAvailabilityApiResponse> GetAvailabilityAsync(string furnitureId)
|
public Task<GetFurnitureAvailabilityResponse> GetAvailabilityAsync(GetFurnitureAvailabilityRequest request)
|
||||||
{
|
{
|
||||||
return Task.FromResult(new GetFurnitureAvailabilityApiResponse(furnitureId, 3));
|
return Task.FromResult(new GetFurnitureAvailabilityResponse(request.FurnitureId, "Chair", 3));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private sealed class FakeFurnitureAvailabilityEdgeContractAdapter : IFurnitureAvailabilityEdgeContractAdapter
|
||||||
|
{
|
||||||
|
public GetFurnitureAvailabilityRequest ToServiceRequest(GetFurnitureAvailabilityApiRequest request)
|
||||||
|
{
|
||||||
|
return new GetFurnitureAvailabilityRequest(request.FurnitureId, request.CorrelationId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public GetFurnitureAvailabilityApiResponse ToApiResponse(GetFurnitureAvailabilityResponse response)
|
||||||
|
{
|
||||||
|
return new GetFurnitureAvailabilityApiResponse(
|
||||||
|
response.FurnitureId,
|
||||||
|
response.DisplayName,
|
||||||
|
response.QuantityAvailable);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user