Swift
JSON
Dictionary
iOS Development
Codable

Convert Dictionary to JSON in Swift

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

Converting a Swift dictionary to JSON is straightforward only when the dictionary contains values that JSON can actually represent. The usual tool for dynamic dictionaries is JSONSerialization, while JSONEncoder is the better choice when the data really has a stable model and should not be treated as [String: Any].

That distinction matters because a Swift dictionary can hold values, such as Date or custom structs, that are not directly valid JSON. Good code checks that first instead of assuming any dictionary can be serialized.

Use JSONSerialization for Dynamic Dictionaries

If the data truly is dynamic at runtime, JSONSerialization is the standard API:

swift
1import Foundation
2
3let dictionary: [String: Any] = [
4    "name": "Ava",
5    "age": 30,
6    "isStudent": false
7]
8
9do {
10    let data = try JSONSerialization.data(
11        withJSONObject: dictionary,
12        options: [.prettyPrinted]
13    )
14    let text = String(data: data, encoding: .utf8)
15    print(text ?? "encoding failed")
16} catch {
17    print("JSON serialization failed:", error)
18}

This works because the values are JSON-compatible:

  • strings
  • numbers
  • booleans
  • arrays
  • nested dictionaries
  • 'NSNull'

If the values stay within those types, the conversion is usually uneventful.

Validate Before Serializing

Swift's [String: Any] is flexible enough to hold values that JSON cannot encode directly. Before serializing, it can be helpful to validate the object graph:

swift
1import Foundation
2
3let payload: [String: Any] = [
4    "name": "Ava",
5    "createdAt": ISO8601DateFormatter().string(from: Date())
6]
7
8if JSONSerialization.isValidJSONObject(payload) {
9    let data = try JSONSerialization.data(withJSONObject: payload, options: [])
10    print(String(data: data, encoding: .utf8) ?? "")
11}

JSONSerialization.isValidJSONObject is a useful guard when the dictionary is assembled dynamically from multiple sources.

Convert Problematic Values First

This will fail:

swift
let badPayload: [String: Any] = [
    "createdAt": Date()
]

Date is a Swift value, not a JSON type. Convert it into a JSON-friendly representation first:

swift
let safePayload: [String: Any] = [
    "createdAt": ISO8601DateFormatter().string(from: Date())
]

The same idea applies to custom models. Either map them into dictionaries manually or stop using [String: Any] and switch to Codable.

Use Codable When the Data Has a Real Shape

If the dictionary is really just a stable model in disguise, encode the model directly instead of passing through a dictionary:

swift
1import Foundation
2
3struct User: Encodable {
4    let name: String
5    let age: Int
6    let isStudent: Bool
7}
8
9let user = User(name: "Ava", age: 30, isStudent: false)
10let data = try JSONEncoder().encode(user)
11print(String(data: data, encoding: .utf8) ?? "")

This is safer because the compiler helps maintain the structure. Once a payload has a predictable schema, [String: Any] usually becomes a liability.

Data Is the Real Output

JSON is fundamentally bytes. Converting to a String is useful for logging, debugging, or tests, but network code often stops at Data.

swift
1import Foundation
2
3var request = URLRequest(url: URL(string: "https://api.example.com/users")!)
4request.httpMethod = "POST"
5request.setValue("application/json", forHTTPHeaderField: "Content-Type")
6request.httpBody = try JSONSerialization.data(withJSONObject: dictionary, options: [])

That is the common reason to convert a dictionary to JSON in the first place.

Common Pitfalls

The most common mistake is assuming any Swift dictionary is automatically JSON-ready. It is not. Values such as Date, URL, custom structs, and arbitrary classes need conversion first.

Another common issue is using [String: Any] for data that really has a stable schema. That throws away type safety and makes both encoding and later maintenance harder than necessary.

Developers also confuse a printed Swift dictionary with JSON text. A Swift dictionary description is not the same thing as valid serialized JSON.

Finally, do not forget that the real payload for networking is usually Data, not a pretty-printed string. String conversion is mainly for human inspection.

Summary

  • Use JSONSerialization for dynamic dictionaries with JSON-compatible values.
  • Validate dynamic payloads with JSONSerialization.isValidJSONObject when helpful.
  • Convert non-JSON values such as Date into strings or numbers first.
  • Prefer Codable and JSONEncoder when the payload has a stable structure.
  • For HTTP requests, the important result is JSON Data, not just a printable string.

Course illustration
Course illustration

All Rights Reserved.