┌─────────────────┐ ┌─────────────────┐
│ Mobile App │ │ Backend │
│ (Hero-payments │ ◄─────► │ mono/api │
│ /mobile) │ GQL │ │
└─────────────────┘ └─────────────────┘
│ │
▼ ▼
App Store GitHub
(users stuck (deploys
on old versions) instantly)
| Mobile | Backend |
|---|---|
| Separate repo | mono repo |
| Release cycle: weeks | Release cycle: daily |
| Users control updates | We control deploys |
| Multiple versions in production | Single version |
A backend developer removes or renames a field...
# Before
type MobileSigninOutput {
token: String!
refreshToken: String!
user: User!
}
# After (breaking change!)
type MobileSigninOutput {
accessToken: String! # renamed!
refreshToken: String!
user: User!
}
┌─────────────────┐
│ Mobile v3.1.0 │ ──► token ──► ❌ Field not found
│ (50% users) │
└─────────────────┘
┌─────────────────┐
│ Mobile v3.2.0 │ ──► accessToken ──► ✅ Works
│ (50% users) │
└─────────────────┘
50% of users have a broken app
| Protection | Catches Breaking Changes? |
|---|---|
| Schema snapshot test | ⚠️ Detects changes, not compatibility |
| Slack notification | ❌ Manual review only |
| Integration tests | ❌ Tests API, not mobile queries |
| Code review | ❌ Human error prone |
Int → String breaks parsingString! → String crashes app| # | Solution | Approach |
|---|---|---|
| 1 | GraphQL Inspector | Validate operations against schema |
| 2 | Codegen Validator | TypeScript compilation check |
| 3 | Schema Contracts | Mobile defines required fields |
| 4 | Operation Registry | S3/npm published operations |
| 5 | Apollo Rover | Apollo Studio schema checks |
| Criteria | Inspector | Codegen | Contracts | Registry | Rover |
|---|---|---|---|---|---|
| Setup effort | Low | Low | High | High | Medium |
| Accuracy | High | Medium | Medium | High | High |
| Error clarity | Excellent | Poor | Good | Good | Good |
| New dependencies | 1 npm | None | Tooling | S3+CI | SaaS |
| Maintenance | Low | Low | Medium | Medium | Low |
@graphql-inspector/cli
Int → String)String! → String)❌ Breaking change detected!
- Field "token" removed from "MobileSigninOutput"
+ Suggestion: Add @deprecated first, remove in 6 months
Affected operations:
└── mobileSignin (src/auth/signin.graphql:12)
Compare to codegen error:
TS2339: Property 'token' does not exist on type...
Block API deployments that break active mobile versions
Automatically. In CI. Before merge.
Schema snapshot already exists:
apps/api/src/00_infra/graphql/
__snapshots__/
graphql.schema.unit.spec.ts.snap ◄── Full SDL schema
Mobile repo with version tags:
github.com/Hero-payments/mobile
tags: v3.2.0, v3.1.0, v3.0.0, ...
┌──────────────┐ ┌──────────────┐ ┌──────────────┐
│ API PR │ │ Mobile Repo │ │ Config │
│ (schema │ │ (GraphQL │ │ (oldest │
│ snapshot) │ │ operations) │ │ version) │
└──────┬───────┘ └──────┬───────┘ └──────┬───────┘
│ │ │
└────────────────────┼────────────────────┘
▼
┌─────────────────┐
│ GraphQL │
│ Inspector │
│ (validates) │
└────────┬────────┘
│
┌────────▼────────┐
│ ✅ Pass / ❌ Fail │
└─────────────────┘
mobile_compatibility:
strategy:
matrix:
mobile-version: [3.2.0, 3.1.0, 3.0.0] # All tags >= oldest
steps:
- checkout api
- checkout mobile @ tag
- run: graphql-inspector validate \
mobile/operations.graphql \
api/schema.snapshot
Note: Oldest version location TBD (config file, env var, etc.)
| Step | Duration |
|---|---|
| Fetch active versions | ~5s |
| Checkout mobile (cached) | ~10s |
| Validate operations | ~15s |
| Total (parallel) | ~30s |
~1 minute added to PR CI (all versions in parallel)
❌ Validation failed for mobile v3.1.0
✖ Field "token" was removed from "MobileSigninOutput"
Used in:
- src/auth/signin.graphql:12
- src/auth/refresh.graphql:8
Breaking for: mobileSignin query
- uses: actions/cache@v4
with:
path: mobile-repo
key: mobile-repo-base
@graphql-inspector/cli
api.pr.yml
Text