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.