Skip to content

πŸ’‘ A smart and resilient JSON decoder for Swift that supports fuzzy key matching, dot-path access, and automatic type casting β€” perfect for dynamic or inconsistent APIs.

Notifications You must be signed in to change notification settings

ihamadfuad/DynamicJSON

Repository files navigation

🧩 DynamicJSON

DynamicJSON is a resilient, smart, and flexible wrapper for decoding and interacting with dynamic or loosely-structured JSON in Swift. It supports fuzzy key matching, automatic type casting, and dot-path access β€” making it ideal for APIs, configuration files, feature flags, and analytics payloads.


πŸ” Before vs After Using DynamicJSON

❌ Before (Vanilla Decoding)

struct Raw: Decodable {
    let feature_toggle: String?
    let darkMode: String?
}

let decoded = try? JSONDecoder().decode(Raw.self, from: jsonData)

let isEnabled = decoded?.feature_toggle == "true"
let isDark = decoded?.darkMode == "on"
  • You need to define intermediate models
  • Compare strings manually
  • Deal with missing keys and nils everywhere

βœ… After (Using DynamicJSON)

let json = try JSONDecoder().decode(DynamicJSON.self, from: jsonData)

let isEnabled = json.featureToggle.bool
let isDark = json.darkMode.bool
  • No need for models
  • One-line type-safe checks
  • Supports formats like "yes", "on", "1", and more

✨ Why DynamicJSON?

Working with JSON in Swift can be painful β€” especially when the structure is inconsistent, values are loosely typed, or keys are formatted in unpredictable ways.

  • Some keys are camelCase, others are snake_case, or even ALLCAPS
  • Values might be "true", true, "1", 1, or "yes" β€” all meaning the same thing
  • Dates can show up in a dozen formats, or even as raw timestamps
  • Typos happen β€” from backend devs or third-party APIs

That’s where DynamicJSON comes in. It’s a smart, forgiving, and developer-friendly way to decode and work with dynamic JSON data. Whether you're pulling feature flags, remote config, analytics events, or responses from external APIs DynamicJSON makes it all seamless.

DynamicJSON handles all of this for you β€” so you don’t have to write dozens of if-lets, custom decoders, or fail silently.

βœ… Normalized key lookup
βœ… Fuzzy match for typos and partial keys
βœ… Smart casting for Bool, Int, Double, String, Date
βœ… Dot-path access for deep nested values
βœ… Dynamic member syntax (json.user.name)
βœ… Type-safe .as() casting method

in other words, you ask for what you want, and it finds it β€” no matter how the data was sent.


πŸ’‘ Key Use Cases

  • πŸ”§ Feature flag systems where keys may be inconsistent or added dynamically
  • πŸ“¦ Remote configuration delivery (AB testing, UI settings, runtime tuning)
  • πŸ“Š Analytics and event tracking systems that send flexible JSON payloads
  • 🌐 APIs that return unpredictable or evolving response schemas
  • πŸ”Œ Third-party integrations where key names and formats can’t be controlled
  • πŸ—‚ Legacy systems with inconsistent formatting and naming conventions
  • πŸ§ͺ Testing tools that need to mock flexible or partial JSON payloads
  • βš™οΈ Backend-driven UI state (e.g., hiding/showing features remotely)
  • πŸ“ JSON-based configuration files or local overrides in development builds
  • 🧡 Telemetry logs and diagnostic data where key/value shape varies per device

πŸ“¦ Installation

.package(url: "https://github.com/ihamadfuad/DynamicJSON.git", from: "1.0.0")

import DynamicJSON

βœ… Features Overview

Category Feature Example or Notes
πŸ”‘ Key Access Dot-path access json["user.settings.notifications.email"]
Dynamic member access json.user.settings.notifications.email
Subscript with format normalization json["UserSettings"] == json.user_settings
Case-insensitive and format-tolerant key matching Matches camelCase, snake_case, kebab-case, etc.
Fuzzy key matching (typo-tolerant) "featurTogle" β†’ "feature_toggle"
Partial key match support "beta" β†’ "beta_feature_x"
Auto-normalized lookup for deep and flat structures Works seamlessly at any nesting depth
πŸ”„ Type Conversion Boolean from string/number/words "true", "yes", "1", 1, etc.
Integer parsing from string, float, bool "25", 25.0, true
Double parsing from string/int/bool "12.5", 1, true
String coercion from bool, number true β†’ "true", 42.0 β†’ "42"
Date parsing from multiple formats ISO8601, MySQL, RFC3339, short, timestamps
Generic .as(T.self) casting json["key"].as(Int.self)
🧩 JSON Structure .array to unwrap JSON arrays Returns [DynamicJSON]?
.dictionary to unwrap objects Returns [String: DynamicJSON]?
.isNull to check for null or missing values Returns true if null or nonexistent
πŸ” Developer Tools Logs fuzzy/partial matches with warnings Helpful for debugging mismatches
Gracefully returns .null instead of crashing on access Safe fallback handling
πŸ›  Use Flexibility Works with deeply nested and mixed-type JSON Great for dynamic payloads
Handles inconsistent or unpredictable backends Makes JSON-safe across the board

πŸš€ Usage Example

{
  "featureToggle": "true",
  "maxItems": "25",
  "discountRate": 12.5,
  "launchDate": "2025-01-01T00:00:00Z",
  "settings": {
    "dark_mode": "on",
    "notifications": {
      "email": "yes",
      "push": false
    }
  }
}
do {
    let json = try JSONDecoder().decode(DynamicJSON.self, from: jsonData)

    let isEnabled = json.featureToggle.bool                  // true
    let maxItems = json["maxItems"].int                      // 25
    let discount = json.discountRate.double                  // 12.5
    let launch = json.launchDate.as(Date.self)               // 2025-01-01

    let emailOn = json.settings.notifications.email.bool     // true
    let pushOn = json["settings.notifications.push"].bool    // false
} catch {
    print("Failed to decode JSON: \(error)")
}

🧠 Smart Key Matching

DynamicJSON will normalize and match keys like: β€’ "FeatureToggle" β†’ "feature_toggle" β€’ "darkMode" β†’ "dark_mode" β€’ "beta-feature-x" β†’ "beta_feature_x" β€’ "FEATURETOGGLE" β†’ "feature_toggle" β€’ "featurTogle" β†’ fuzzy match β†’ "feature_toggle"

πŸ“… Date Parsing

Supports: β€’ 2024-01-01T12:34:56Z β€’ 2024-01-01T12:34:56.123Z β€’ 2024-01-01 12:34:56 β€’ 2024-01-01 β€’ 01/01/2024 β€’ 01-01-2024 β€’ UNIX timestamp & with milisoconds: 1704067200 or 1704067200000

πŸ”¬ More in depth

Accessors

json["key"]
json.key
json["nested.key.path"]
json.key.bool / .int / .double / .string / .date
json.key.as(Int.self)

Containers

json.array β†’ [DynamicJSON]?
json.dictionary β†’ [String: DynamicJSON]?
json.isNull β†’ Bool

🎯 Frequently Asked Questions

❓ What happens if a key is missing?

You’ll get .null back. You can check using json["key"].isNull or safely unwrap optional values.


❓ Will this crash if the JSON is malformed?

No. If decoding fails, it throws like any regular Decodable type. Accessing values afterward will never crash β€” you’ll just get nil or .null.


❓ Does it work with nested objects and arrays?

Yes. You can drill down using dot-paths (json["user.settings.notifications"]) or dynamic members (json.user.settings.notifications).


❓ Can I use it alongside regular Codable structs?

Absolutely. Use DynamicJSON for dynamic/unknown parts of the payload, and Codable for strict parts.


❓ What date formats are supported?

Out of the box:

  • ISO8601
  • RFC3339 with milliseconds
  • MySQL datetime (yyyy-MM-dd HH:mm:ss)
  • Short format (yyyy-MM-dd)
  • Timestamps in seconds and milliseconds

❓ How is it different from [String: Any]?

Unlike [String: Any], DynamicJSON is type-safe, supports dot access, fuzzy keys, smart casting, and works with Swift’s Decodable.


❓ Can I use this in production apps?

Yes β€” it's designed to be resilient, readable, and production-safe.


❓ Will this impact performance?

Key normalization and fuzzy matching are optimized and fast for typical payloads. If needed, you can disable fuzzy matching in future versions.


❓ What Swift versions are supported?

Swift 5.9 and later (uses modern Decodable patterns and dynamic member lookup).


❓ Is this tested?

Yes β€” it includes extensive tests for decoding, type coercion, fuzzy keys, date formats, and more.

About

πŸ’‘ A smart and resilient JSON decoder for Swift that supports fuzzy key matching, dot-path access, and automatic type casting β€” perfect for dynamic or inconsistent APIs.

Topics

Resources

Stars

Watchers

Forks

Packages

No packages published

Languages