Client Area

Building Backend APIs for Mobile Apps (iOS, Android, Flutter) on DomainIndia Hosting

ByDomain India Team·DomainIndia Engineering
6 min read24 Apr 20264 views
# Building Backend APIs for Mobile Apps (iOS, Android, Flutter) on DomainIndia Hosting
TL;DR
Mobile apps need a backend. This guide covers REST vs GraphQL for mobile, authentication (JWT, OAuth, biometric), push notifications (FCM + APNs), file uploads, offline sync, and choosing the right DomainIndia hosting tier for your app's stage.
## What mobile backends must handle Every mobile app (iOS, Android, React Native, Flutter) talks to a backend for: - User signup / login (email, Google, Apple, phone OTP) - Content feeds — loaded lazily, paginated - File uploads (profile photos, documents, audio) - Push notifications - Real-time updates (chat, live scores, order tracking) - Analytics events - Payments (Razorpay/Stripe for Indian + global markets) - Offline sync (app works without internet, syncs on reconnect) ## Which DomainIndia plan?
App stageMAU (monthly active users)Recommended plan
Prototype / testing<1,000Shared cPanel with Node.js or Laravel
MVP / growing1,000 – 10,000VPS Starter (2 GB)
Production / scaling10,000 – 100,000VPS Business (4 GB) + Cloudflare CDN
High-scale100,000+Multi-VPS + load balancer + managed PostgreSQL
Mobile backends are API-only (no HTML rendering), so they're efficient. A 2 GB VPS easily handles 10,000 MAU for a typical social/commerce app. ## Choosing the API style **REST** — simple, works everywhere, easy caching. Best default. **GraphQL** — thin clients love minimal payloads over 3G. See our [GraphQL APIs article](https://domainindia.com/support/kb/category/dev-graphql). **gRPC** — internal microservices; rarely used client-side for mobile (except streaming/IoT). **WebSockets / Server-Sent Events** — real-time (chat, live trackers). For most Indian apps: REST with JSON + WebSockets for real-time features. Add GraphQL only if you have multiple mobile platforms with different field needs. ## Authentication patterns ### Pattern 1 — JWT with refresh tokens Classic for mobile. Apps can't keep a cookie-based session easily.
1
User logs in with email + password (or social OAuth)
2
Backend issues:
3
Every API call sends Authorization: Bearer <access_token>
4
Before expiry, app POSTs refresh token → gets new access token
5
Refresh token can be revoked server-side (logout all devices)
Node.js example: ```javascript import jwt from 'jsonwebtoken'; function issueTokens(userId) { const accessToken = jwt.sign({ sub: userId }, ACCESS_SECRET, { expiresIn: '15m' }); const refreshToken = jwt.sign({ sub: userId, type: 'refresh' }, REFRESH_SECRET, { expiresIn: '30d' }); // Store hash of refresh token in DB for revocation db.refreshToken.create({ userId, hash: sha256(refreshToken), expiresAt: ... }); return { accessToken, refreshToken }; } // Client calls POST /auth/refresh with the refresh token: app.post('/auth/refresh', async (req, res) => { const { refreshToken } = req.body; const payload = jwt.verify(refreshToken, REFRESH_SECRET); const stored = await db.refreshToken.findFirst({ where: { hash: sha256(refreshToken) } }); if (!stored || stored.revoked) return res.status(401).json({ error: 'Invalid' }); res.json(issueTokens(payload.sub)); }); ``` ### Pattern 2 — OAuth (Sign in with Apple / Google) Mandatory for iOS apps that offer any other login (App Store rule). Google Sign-In covers Android. - iOS: Apple Sign-In, returns identity token, verify signature against Apple's JWK - Android: Google Sign-In, same pattern with Google JWK Your backend stores a `provider + providerUserId → internalUserId` mapping. ### Pattern 3 — Biometric unlock (local) Device unlocks the refresh token using FaceID / fingerprint, then sends it to your API. Your API doesn't know or care about biometrics — it just sees refresh → access. ## Push notifications Two providers: **Firebase Cloud Messaging (FCM)** for Android + cross-platform, **Apple Push Notification service (APNs)** for iOS. Easiest path: use FCM for both. Firebase handles APNs relay for you.
1
Create Firebase project, add iOS + Android apps
2
Download google-services.json (Android) + GoogleService-Info.plist (iOS)
3
App registers with FCM on first launch → gets device token → POSTs to your /push/register endpoint
4
Backend stores userId ↔ deviceToken mapping
5
To notify:
Libraries: `firebase-admin` (Node), `pyfcm` (Python), `kreait/firebase-php`. ## File uploads Mobile devices upload photos, videos, documents. Strategies: **Direct-to-S3 (or Backblaze B2) with presigned URLs** — recommended. - Client requests `POST /upload-url` with filename + content-type - Backend returns a 10-minute signed URL to upload directly to S3 - Client PUTs the file to S3; no hop through your API - Client notifies backend with the final S3 key Saves your VPS bandwidth + CPU. Scales infinitely. **Through-your-API upload** — only for small files (<5 MB). Simpler but consumes VPS RAM/bandwidth. ```javascript import multer from 'multer'; const upload = multer({ limits: { fileSize: 5 * 1024 * 1024 }, dest: '/tmp/' }); app.post('/upload', upload.single('file'), async (req, res) => { const key = `users/${req.user.id}/${Date.now()}-${req.file.originalname}`; await s3.putObject({ Bucket: 'uploads', Key: key, Body: fs.createReadStream(req.file.path) }); res.json({ url: `https://cdn.yourcompany.com/${key}` }); }); ``` ## Offline sync Users in India's metro-to-tier-2 transitions (weak 4G, metro tunnels) demand offline-first apps. Patterns: 1. **Optimistic writes** — app writes to local SQLite first, then syncs. Show "syncing..." indicator. 2. **Pull-based sync with timestamps** — `GET /sync?since=` returns changes. Client applies. 3. **Realm / WatermelonDB / PowerSync** — libraries that handle sync for you. Backend needs: - `updatedAt` timestamp on every row (auto-update on change) - Soft deletes (flag `deletedAt`, don't hard-delete) - Tombstone endpoint listing deleted IDs since timestamp ## Payments (Indian market) Primary: **Razorpay** (UPI, cards, netbanking, wallets, subscriptions). Alternative: **Stripe** (cards, international). Mobile integration uses their official SDKs — your backend creates the order on Razorpay API, passes order ID to app, app opens Razorpay Checkout, app sends signature back to backend for verification. See [our Razorpay Integration article](https://domainindia.com/support/kb/razorpay-integration-php-nodejs). ## Versioning your API Mobile apps don't auto-update — expect users running 6-month-old app versions for years. Pattern: **version your API URL** (`/v1/`, `/v2/`) and keep old versions running indefinitely. ``` GET /v1/feed # legacy — keep forever GET /v2/feed # current GET /v3/feed # next ``` If you can't maintain N versions forever, use feature-flagged responses keyed by the `User-Agent` or a custom `X-App-Version` header. ## Security essentials ## FAQ
Q Can I host a mobile backend on shared cPanel?

Yes for prototypes and small apps (<1K users). Node.js via Setup Node.js App, or Laravel/Rails for traditional stacks. For serious traffic, upgrade to VPS.

Q Do I need a separate dev / staging / production?

Yes. Mobile apps can't "hotfix" server bugs — apps run against whatever backend version they target. Never point new app builds at production until tested on staging.

Q How much does mobile backend cost at 100K users?

Typical stack on DomainIndia: VPS Business (~₹3,000/mo) + PostgreSQL managed or self-hosted + S3-compatible storage (~₹500/mo) + Cloudflare Free + FCM Free = ~₹4,000/mo total. Scales linearly with active usage.

Q React Native vs Flutter vs native — does the backend change?

No. Your API is stack-agnostic. Pick frontend based on team skills. Backend stays the same.

Q Should I use Firebase instead of a custom backend?

Firebase is faster to launch (auth, DB, push, storage bundled) but vendor-locked and costly past ~10K MAU. Custom on DomainIndia gives you full control and predictable costs.

Build your mobile API with predictable costs and full control. See our VPS plans

Was this article helpful?

Your feedback helps us improve our documentation

Still need help? Submit a support ticket