Triton/Documentation/ADR/ADR-007-microclient-for-http-communication.md
Otávio 3e878667a1 Add Triton App
Signed-off-by: Otavio Cordeiro <otaviocc@users.noreply.github.com>
2025-12-15 20:39:07 +01:00

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:

  1. URLSession directly: Apple's native networking, but requires significant boilerplate
  2. Alamofire: Popular third-party library with extensive features
  3. 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:

  1. OMGAPIFactory: Central factory for creating HTTP requests using MicroClient's NetworkRequest
  2. Request/Response models: DTOs defined in OMGAPI package
  3. NetworkService layer: Each feature's NetworkService uses MicroClient
  4. Async/await: All network calls use async/await for clean asynchronous code
  5. 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:

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.