04
Product
16
Backend
09
Auth
12
iOS
07
Infra
02
Real-Time
ADR-0048 ACCEPTED · 2025-07-10
Use async-graphql for the API layer

Context

The app needs an API layer between the iOS client and Rust backend. REST is the default, but Apollo iOS provides a normalized cache that acts as a source of truth for the UI (ADR-0003). That cache works best with GraphQL — the client declares exactly what data it needs, the cache normalizes and deduplicates it, and watched queries update the UI automatically.

The Rust GraphQL ecosystem has two main options: async-graphql and juniper. async-graphql has better integration with Axum, built-in subscription support, and a derive-macro approach that fits well with the domain structure (ADR-0009).

Decision

Use async-graphql with Axum as the API layer. Schema is defined via Rust derive macros on domain types. Each domain exposes its resolvers in graphql.rs, keeping GraphQL concerns separate from business logic in types.rs and service.rs.

Custom multipart subscription transport supports Apollo iOS v2, which doesn't have WebSocket subscription support (tracked at apollographql/apollo-ios#3624).

Consequences

Type-safe schema derived from Rust types — schema changes are compile errors, not runtime surprises. Apollo iOS normalized cache provides automatic UI updates, offline support, and component-specific queries (ADR-0031).

The cost is GraphQL complexity (subscriptions, multipart transport, schema evolution) compared to REST, and a tighter coupling between client and server schema.