4 KiB
ADR-007: MicroClient for HTTP Communication
Status: Accepted
Date: 2025-01-11
Context:
When designing the networking layer for the OMG application, I needed to choose an HTTP client library. The options included:
- URLSession directly: Apple's native networking, but requires significant boilerplate
- Alamofire: Popular third-party library with extensive features
- MicroClient: Lightweight Swift-first HTTP client I built on top of URLSession
Key considerations:
- Simplicity: Needed clean API for straightforward HTTP requests
- Modern Swift: Should work naturally with async/await
- Type safety: Compile-time safety for requests and responses
- Control: Ability to customize exactly for this application's needs
- Boilerplate reduction: Less code than raw URLSession
Decision:
I chose to build and use MicroClient as the HTTP communication library for the OMG application. It provides a clean, type-safe API built on top of URLSession without the complexity of larger networking frameworks, tailored specifically to my needs.
Key Implementation Patterns:
- OMGAPIFactory: Central factory for creating HTTP requests using MicroClient's
NetworkRequest - Request/Response models: DTOs defined in OMGAPI package
- NetworkService layer: Each feature's NetworkService uses MicroClient
- Async/await: All network calls use async/await for clean asynchronous code
- Interceptors: Authentication and common headers handled via MicroClient interceptors
Example Usage:
// In OMGAPIFactory - creates typed requests
extension OMGAPIFactory {
static func makeAllStatusesRequest() -> NetworkRequest<VoidRequest, StatuslogResponse> {
.init(
path: "/statuslog",
method: .get
)
}
}
// In NetworkService - executes requests
actor StatusNetworkService {
private let client: MicroClient
func fetchStatuses() async throws -> StatuslogResponse {
let request = OMGAPIFactory.makeAllStatusesRequest()
return try await client.run(request)
}
}
Consequences:
Positive
- Clean API: Simpler than raw URLSession, focused on actual needs
- Type safety: Request and response types checked at compile time via
NetworkRequest<Request, Response> - Async/await native: Built for modern Swift concurrency
- Lightweight: Minimal dependency footprint
- Full control: Can evolve the library alongside the application
- Tailored design: API shaped exactly for this application's patterns
- Flexible: Can add interceptors for auth, logging, etc.
Negative
- Maintenance responsibility: I maintain the library
- Documentation: Need to document patterns for my future reference
- External use consideration: Library evolved alongside this specific application
Neutral
- Dependency management: External dependency, but under my control
- Feature scope: Only implements features needed by this application
Integration with Architecture:
- OMGAPI package: Contains OMGAPIFactory and all request/response DTOs
- NetworkService layer: Each feature's NetworkService depends on OMGAPI and uses MicroClient
- Repository coordination: Repositories consume NetworkService protocols
- Error handling: Network errors handled at repository boundary, mapped to domain errors
Related Decisions:
- ADR-002: Layered Architecture and Dependency Direction - MicroClient used in NetworkService layer
- ADR-004: Migration from Combine to Async/Await - MicroClient built with async/await support
- ADR-012: DTO-Based Data Flow - Request/response models in OMGAPI
Notes:
Building MicroClient gave me full control over the networking layer's API design and allowed me to create a library that fits perfectly with the application's architecture and patterns. The NetworkRequest<Request, Response> type provides compile-time safety for API calls.