Facade Pattern — Simplified Module API
Definition
Section titled “Definition”The Facade pattern provides a simplified interface to a complex subsystem. It hides the complexity of interactions between multiple components behind a single, cohesive entry point.
Diagram
Section titled “Diagram”classDiagram
class IBlobStorage {
+InitiateUploadAsync()
+CreateDownloadUrlAsync()
+DeleteAsync()
}
class DefaultBlobStorage {
-currentTenant : ICurrentTenant
-reader : IBlobDescriptorReader
-writer : IBlobDescriptorWriter
-keyStrategy : IBlobKeyStrategy
-storeProvider : IBlobStoreProvider
-presignedUrlProvider : IPresignedUrlProvider
-validators : IBlobValidator[]
-clock : IClock
}
class GranitExceptionHandler {
-mappers : IExceptionStatusCodeMapper[]
-logger : ILogger
}
DefaultBlobStorage ..|> IBlobStorage
DefaultBlobStorage --> IBlobDescriptorReader
DefaultBlobStorage --> IBlobDescriptorWriter
DefaultBlobStorage --> IBlobKeyStrategy
DefaultBlobStorage --> IBlobStoreProvider
DefaultBlobStorage --> IPresignedUrlProvider
DefaultBlobStorage --> IBlobValidator
Implementation in Granit
Section titled “Implementation in Granit”| Facade | File | Orchestrated sub-components |
|---|---|---|
DefaultBlobStorage | src/Granit.BlobStorage/Internal/DefaultBlobStorage.cs | ICurrentTenant, IBlobDescriptorReader, IBlobDescriptorWriter, IBlobKeyStrategy, IBlobStoreProvider, IPresignedUrlProvider, IBlobValidator[], IGuidGenerator, IClock |
GranitExceptionHandler | src/Granit.Http.ExceptionHandling/Internal/GranitExceptionHandler.cs | IExceptionStatusCodeMapper[], ILogger, ExceptionHandlingOptions |
Rationale
Section titled “Rationale”Without the DefaultBlobStorage facade, application code would have to
manually orchestrate tenant resolution, S3 key generation, descriptor
creation, presigned URL generation, and validation — on every operation. The
facade encapsulates this complexity behind 3 public methods.
GranitExceptionHandler centralizes exception-to-ProblemDetails conversion
(RFC 7807), hiding the mapper chain and ISO 27001 rules (masking internal
details in production).
Usage example
Section titled “Usage example”// The caller interacts with a simple API -- complexity is hiddenIBlobStorage blobStorage = serviceProvider.GetRequiredService<IBlobStorage>();
// Behind this call: tenant resolution, descriptor creation,// S3 key generation, presigned URL, database persistencePresignedUploadTicket ticket = await blobStorage.InitiateUploadAsync( "avatars", new BlobUploadRequest("photo.jpg", "image/jpeg", MaxAllowedBytes: 5_000_000), cancellationToken);