JSON Parsing Across Platforms
| Feature | Swift (iOS) | Kotlin (Android) | React Native |
|---|---|---|---|
| Parser | JSONDecoder (Codable) | kotlinx.serialization | JSON.parse / Zod |
| Type safety | Compile-time (Codable) | Compile-time (@Serializable) | Runtime (Zod/io-ts) |
| Key mapping | CodingKeys enum | @SerialName annotation | Manual or transform |
| Date handling | .iso8601 strategy | kotlinx-datetime | new Date(string) |
| Null safety | Optional (String?) | Nullable (String?) | Optional chaining |
| Offline cache | Core Data / FileManager | Room / DataStore | AsyncStorage / MMKV |
1. Swift — Codable (iOS / macOS)
Define a Codable modelswift
1struct User: Codable {2 let id: Int3 let name: String4 let email: String5 let bio: String? // nullable field6 let createdAt: Date7 let settings: UserSettings89 struct UserSettings: Codable {10 let theme: String11 let notifications: Bool12 }1314 // Map JSON keys to Swift properties15 enum CodingKeys: String, CodingKey {16 case id, name, email, bio, settings17 case createdAt = "created_at" // snake_case → camelCase18 }19}Fetch and parse JSONswift
1func fetchUsers() async throws -> [User] {2 let url = URL(string: "https://api.example.com/users")!3 let (data, response) = try await URLSession.shared.data(from: url)45 guard let httpResponse = response as? HTTPURLResponse,6 httpResponse.statusCode == 200 else {7 throw APIError.invalidResponse8 }910 let decoder = JSONDecoder()11 decoder.dateDecodingStrategy = .iso860112 decoder.keyDecodingStrategy = .convertFromSnakeCase1314 return try decoder.decode([User].self, from: data)15}1617// Usage in SwiftUI18struct UserListView: View {19 @State private var users: [User] = []2021 var body: some View {22 List(users, id: \.id) { user in23 VStack(alignment: .leading) {24 Text(user.name).font(.headline)25 Text(user.email).font(.caption)26 }27 }28 .task {29 users = (try? await fetchUsers()) ?? []30 }31 }32}Tip
Use
keyDecodingStrategy: .convertFromSnakeCase to automatically convert snake_case JSON keys to camelCase Swift properties, eliminating the need for manual CodingKeys in most cases.2. Kotlin — kotlinx.serialization (Android)
Define a serializable modelkotlin
1import kotlinx.serialization.Serializable2import kotlinx.serialization.SerialName3import kotlinx.serialization.json.Json45@Serializable6data class User(7 val id: Int,8 val name: String,9 val email: String,10 val bio: String? = null, // nullable with default11 @SerialName("created_at")12 val createdAt: String, // ISO string13 val settings: UserSettings = UserSettings()14)1516@Serializable17data class UserSettings(18 val theme: String = "light",19 val notifications: Boolean = true20)2122// Configure parser23val json = Json {24 ignoreUnknownKeys = true // Don't crash on extra fields25 isLenient = true // Accept unquoted values26 coerceInputValues = true // Coerce nulls to defaults27 encodeDefaults = false // Skip default values in output28}Parse JSON with Ktor clientkotlin
1import io.ktor.client.*2import io.ktor.client.call.*3import io.ktor.client.request.*4import kotlinx.serialization.json.Json56suspend fun fetchUsers(): List<User> {7 val client = HttpClient()8 val response: String = client.get("https://api.example.com/users").body()9 return json.decodeFromString<List<User>>(response)10}1112// Serialize to JSON13val user = User(id = 1, name = "Alice", email = "[email protected]", createdAt = "2026-04-02T14:30:00Z")14val jsonString = json.encodeToString(User.serializer(), user)3. React Native — fetch + Zod
Type-safe API fetch in React Nativetypescript
1import { z } from 'zod';23const UserSchema = z.object({4 id: z.number(),5 name: z.string(),6 email: z.string().email(),7 bio: z.string().nullable(),8 created_at: z.string().datetime(),9 settings: z.object({10 theme: z.enum(['light', 'dark']),11 notifications: z.boolean(),12 }),13});1415type User = z.infer<typeof UserSchema>;1617async function fetchUsers(): Promise<User[]> {18 const response = await fetch('https://api.example.com/users');19 if (!response.ok) throw new Error(`HTTP ${response.status}`);2021 const data = await response.json();22 return z.array(UserSchema).parse(data); // Validates at runtime23}Common Mobile JSON Pitfalls
1. Crashing on Unexpected null
1// API sometimes returns null for "name"2// WRONG — will crash if null3struct User: Codable {4 let name: String // Fatal error if JSON has null5}67// CORRECT — use Optional8struct User: Codable {9 let name: String? // Gracefully handles null10}2. Ignoring Unknown Keys
1// API adds a new field "avatar_url" — your app crashes2// WRONG — strict parsing3val json = Json { }45// CORRECT — ignore unknown keys6val json = Json { ignoreUnknownKeys = true }3. Not Handling Empty Responses
1// React Native: 204 No Content returns empty body2const response = await fetch('/api/resource', { method: 'DELETE' });3// WRONG — crashes on empty body4const data = await response.json();56// CORRECT — check status first7if (response.status === 204) {8 return null;9}10const data = await response.json();Try It — Validate a Mobile API Response
Try It Yourself
A typical user JSON response consumed by mobile apps
Try These Tools
Continue Learning
Frequently Asked Questions
What is Swift Codable?
Codable is a Swift protocol that combines Encodable and Decodable. When your struct conforms to Codable, Swift can automatically convert between JSON and your type using JSONDecoder and JSONEncoder. It handles key mapping, nested objects, and optional fields with minimal boilerplate.
Should I use Gson, Moshi, or kotlinx.serialization in Android?
kotlinx.serialization is the modern choice — it is maintained by JetBrains, supports multiplatform, and works at compile-time (no reflection). Moshi is a solid alternative with Kotlin-first design. Gson is legacy and less Kotlin-friendly. For new projects, use kotlinx.serialization.
How do I handle date formats in mobile JSON?
Use ISO 8601 strings ("2026-04-02T14:30:00Z") in your JSON API. In Swift, configure JSONDecoder with dateDecodingStrategy: .iso8601. In Kotlin, parse with kotlinx-datetime or java.time.Instant. Avoid Unix timestamps unless the API requires them.
How do I cache JSON for offline use?
In Swift, save to UserDefaults (small), FileManager (medium), or Core Data (complex). In Kotlin/Android, use DataStore (key-value), Room (relational), or file storage. In React Native, use AsyncStorage or MMKV. Always serialize to JSON strings before storing.
How do I handle null vs missing fields in mobile JSON?
In Swift, use Optional properties (let bio: String?). Missing or null JSON fields map to nil. In Kotlin, use nullable types (val bio: String?). In React Native/TypeScript, use optional types and default values. Always design your models to handle both null and absent fields gracefully.