Return GraphQL error codes in extensions and localize them on iOS
Decision
Put a machine-readable code in extensions.code on every GraphQL error. The iOS app reads the code and maps it to a string from its own string catalog through LocalizedError. The server sends no user-facing prose.
Domain codes cover failures a user can understand and act on, such as a rejected input or a denied permission. An infrastructure failure, such as a database or Redis error, surfaces under a generic application code like DATABASE_ERROR or INTERNAL_SERVER_ERROR, and the app shows a generic message for it.
Why
The server can't know the user's language, and iOS already has a localization pipeline that Xcode and translators understand. A client that matches on English wording breaks whenever someone rewords a message. A code is a stable contract that tests and client logic can switch on.
Rejected alternatives
- English messages written by the server. The API would carry one language, and clients and tests would match on wording that anyone can change. It also bypasses the platform's localization.
- Server-side localization keyed on
Accept-Language. The server would keep a translation catalogue for every language the app ships, beside the app's own catalogue, and every client would have to send its locale correctly.
Consequences
The API carries no language, and tests assert codes. A new code needs a server change and an app change before the user sees a specific message for it.