HTTP Request Decorators
Decorators allow you to modify every outgoing HTTP request before it is sent. Common use cases include adding authentication tokens, injecting device information headers, or appending correlation IDs.
What Are Decorators?
Section titled “What Are Decorators?”An HTTP request decorator implements IHttpRequestDecorator and runs against every HTTP request made through the Mediator HTTP extension. This is different from middleware - decorators operate on the raw HttpRequestMessage rather than the mediator pipeline.
Decorators apply to all HTTP requests made through the Mediator HTTP extension.
IHttpRequestDecorator Interface
Section titled “IHttpRequestDecorator Interface”public interface IHttpRequestDecorator{ Task Decorate(HttpRequestMessage httpMessage, IMediatorContext context);}The Decorate method receives:
httpMessage- The outgoingHttpRequestMessageyou can modify (add headers, set auth, etc.)context- The mediator context containing the original request contract and any context values
Authentication Decorator
Section titled “Authentication Decorator”A common scenario is refreshing an access token and adding it to the request:
public class AuthHttpRequestDecorator(IAuthService authService) : IHttpRequestDecorator{ public async Task Decorate(HttpRequestMessage httpMessage, IMediatorContext context) { // Refresh token if expired if (authService.TokenExpiry < DateTimeOffset.UtcNow) await authService.RefreshToken();
httpMessage.Headers.Authorization = new AuthenticationHeaderValue( "Bearer", authService.AccessToken ); }}Device/App Info Decorator
Section titled “Device/App Info Decorator”The Shiny.Mediator.Maui package includes a built-in decorator that adds device and app information headers. Here’s a similar example showing the pattern:
public class MauiHttpRequestDecorator( IConfiguration configuration, IAppInfo appInfo, IDeviceInfo deviceInfo, IGeolocation geolocation) : IHttpRequestDecorator{ public async Task Decorate(HttpRequestMessage httpMessage, IMediatorContext context) { httpMessage.Headers.Add("AppId", appInfo.PackageName); httpMessage.Headers.Add("AppVersion", appInfo.Version.ToString()); httpMessage.Headers.Add("DeviceManufacturer", deviceInfo.Manufacturer); httpMessage.Headers.Add("DeviceModel", deviceInfo.Model); httpMessage.Headers.Add("DevicePlatform", deviceInfo.Platform.ToString()); httpMessage.Headers.Add("DeviceVersion", deviceInfo.Version.ToString()); httpMessage.Headers.AcceptLanguage.Add( new StringWithQualityHeaderValue(CultureInfo.CurrentCulture.Name) );
if (configuration["Mediator:Http:GpsHeader"] == "true") { var gps = await geolocation.GetLastKnownLocationAsync(); if (gps != null) httpMessage.Headers.Add("GpsCoords", $"{gps.Latitude},{gps.Longitude}"); } }}Common Decorator Patterns
Section titled “Common Decorator Patterns”API Key Injection
Section titled “API Key Injection”public class ApiKeyDecorator(IConfiguration config) : IHttpRequestDecorator{ public Task Decorate(HttpRequestMessage httpMessage, IMediatorContext context) { var apiKey = config["ApiKey"]; httpMessage.Headers.Add("X-Api-Key", apiKey); return Task.CompletedTask; }}Correlation ID
Section titled “Correlation ID”public class CorrelationIdDecorator : IHttpRequestDecorator{ public Task Decorate(HttpRequestMessage httpMessage, IMediatorContext context) { httpMessage.Headers.Add("X-Correlation-Id", Guid.NewGuid().ToString()); return Task.CompletedTask; }}Locale Header
Section titled “Locale Header”public class LocaleDecorator : IHttpRequestDecorator{ public Task Decorate(HttpRequestMessage httpMessage, IMediatorContext context) { httpMessage.Headers.AcceptLanguage.Add( new StringWithQualityHeaderValue(CultureInfo.CurrentCulture.Name) ); return Task.CompletedTask; }}Multiple Decorators
Section titled “Multiple Decorators”You can register multiple decorators and they will all run on every HTTP request. Register them with dependency injection:
services.AddSingletonAsImplementedInterfaces<AuthHttpRequestDecorator>();services.AddSingletonAsImplementedInterfaces<CorrelationIdDecorator>();services.AddSingletonAsImplementedInterfaces<LocaleDecorator>();