{"id":17923146,"url":"https://github.com/rogerluan/jsen","last_synced_at":"2025-09-30T01:31:57.907Z","repository":{"id":38913776,"uuid":"376298320","full_name":"rogerluan/JSEN","owner":"rogerluan","description":"JSEN (JSON Swift Enum Notation) is a lightweight enum representation of a JSON, written in Swift.","archived":false,"fork":false,"pushed_at":"2024-07-16T04:15:58.000Z","size":75,"stargazers_count":13,"open_issues_count":0,"forks_count":2,"subscribers_count":3,"default_branch":"main","last_synced_at":"2025-01-14T04:31:12.569Z","etag":null,"topics":["ios","json","spm","swift"],"latest_commit_sha":null,"homepage":null,"language":"Swift","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"bsd-2-clause","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/rogerluan.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2021-06-12T13:36:28.000Z","updated_at":"2024-07-16T04:16:01.000Z","dependencies_parsed_at":"2024-07-16T07:10:58.320Z","dependency_job_id":null,"html_url":"https://github.com/rogerluan/JSEN","commit_stats":{"total_commits":24,"total_committers":2,"mean_commits":12.0,"dds":0.08333333333333337,"last_synced_commit":"52a16b43003dde307ea8ce9438ffd805075cff40"},"previous_names":[],"tags_count":7,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rogerluan%2FJSEN","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rogerluan%2FJSEN/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rogerluan%2FJSEN/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rogerluan%2FJSEN/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/rogerluan","download_url":"https://codeload.github.com/rogerluan/JSEN/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":234685347,"owners_count":18871446,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["ios","json","spm","swift"],"created_at":"2024-10-28T20:42:19.141Z","updated_at":"2025-09-30T01:31:57.618Z","avatar_url":"https://github.com/rogerluan.png","language":"Swift","funding_links":[],"categories":[],"sub_categories":[],"readme":"# JSEN\n\n\u003cp\u003e\n  \u003ca href=\"https://github.com/rogerluan/JSEN/actions/workflows/run_tests.yml\"\u003e\n    \u003cimg src=\"https://github.com/rogerluan/JSEN/workflows/Run%20Tests/badge.svg\" alt=\"GitHub Action Build Status\" /\u003e\n  \u003c/a\u003e\n  \u003ca href=\"https://swift.org\"\u003e\n    \u003cimg src=\"https://img.shields.io/badge/Swift-5.4-F05138?logo=swift\u0026logoColor=white\" alt=\"Swift 5.4\" /\u003e\n  \u003c/a\u003e\n  \u003cimg src=\"https://img.shields.io/static/v1?label=Platforms\u0026message=iOS%20|%20macOS%20|%20tvOS%20|%20watchOS%20|%20Ubuntu%20\u0026color=brightgreen\" alt=\"Supports iOS, macOS, tvOS, watchOS and Ubuntu\" /\u003e\n\n  \u003ca href=\"https://github.com/rogerluan/JSEN/releases/latest\"\u003e\n    \u003cimg src=\"https://img.shields.io/github/v/release/rogerluan/JSEN?sort=semver\" alt=\"Latest release\" /\u003e\n  \u003c/a\u003e\n\n  \u003cimg src=\"https://views.whatilearened.today/views/github/rogerluan/jsen.svg\"\u003e\n  \n  \u003ca href=\"https://codeclimate.com/github/rogerluan/JSEN/maintainability\"\u003e\u003cimg src=\"https://api.codeclimate.com/v1/badges/e78e3c33607e8575b1e8/maintainability\" /\u003e\u003c/a\u003e\n\u003c/p\u003e\n\n\u003e _/ˈdʒeɪsən/ JAY-sən_\n\nJSEN (JSON Swift Enum Notation) is a lightweight enum representation of a JSON, written in Swift.\n\nA JSON, as defined in the [ECMA-404 standard](https://www.json.org), can be:\n\n- A number\n- A boolean\n- A string\n- Null\n- An array of those things\n- A dictionary of those things\n\nThus, JSONs can be represented as a recursive enum (or `indirect enum`, in Swift), effectively creating a statically-typed JSON payload in Swift.\n\n# Why would I use this?\n\nThis is the type safe version of the infamous `[String:Any]` that is present everywhere in your codebase, to represent JSONs. If you love Swift, this should be enough of an argument already 😉 If not, keep reading to discover all the syntactic sugar present in this simple enum!\n\n# Installation\n\nUsing Swift Package Manager:\n\n```swift\ndependencies: [\n    .package(name: \"JSEN\", url: \"https://github.com/rogerluan/JSEN\", .upToNextMajor(from: \"1.0.0\")),\n]\n```\n\n# Usage\n\nI think it's essential for the understanding of how simple this is, for you to visualize the JSEN declaration:\n\n```swift\n/// A simple JSON value representation using enum cases.\npublic enum JSEN : Equatable {\n    /// An integer value.\n    case int(Int)\n    /// A floating point value.\n    case double(Double)\n    /// A string value.\n    case string(String)\n    /// A boolean value.\n    case bool(Bool)\n    /// An array value in which all elements are also JSEN values.\n    indirect case array([JSEN])\n    /// An object value, also known as dictionary, hash, and map.\n    /// All values of this object are also JSEN values.\n    indirect case dictionary([String:JSEN])\n    /// A null value.\n    case null\n}\n```\n\nThat's it.\n\n### `ExpressibleBy…Literal`\n\nNow that you're familiar with JSEN, it provides a few syntactic sugary utilities, such as conformance to most `ExpressibleBy…Literal` protocols:\n\n- `ExpressibleByIntegerLiteral` initializer returns an `.int(…)`.\n- `ExpressibleByFloatLiteral` initializer returns a `.double(…)`.\n- `ExpressibleByStringLiteral` initializer returns a  `.string(…)`.\n- `ExpressibleByBooleanLiteral` initializer returns a `.bool(…)`.\n- `ExpressibleByArrayLiteral` initializer returns an `.array(…)` as long as its Elements are JSENs.\n- `ExpressibleByDictionaryLiteral` initializer returns an `.dictionary(…)` as long as its keys are Strings and Values JSENs.\n- `ExpressibleByNilLiteral` initializer returns a `.null`.\n\nConformance to `ExpressibleBy…Literal` protocols are great when you want to build a JSON structure like this:\n\n```swift\nlet request: [String:JSEN] = [\n    \"key\": \"value\",\n    \"another_key\": 42,\n]\n```\n\nBut what if you're not working with literals?\n\n```swift\nlet request: [String:JSEN] = [\n    \"amount\": normalizedAmount // This won't compile\n]\n```\n\nEnters the…\n\n### `%` Prefix Operator\n\n```swift\nlet request: [String:JSEN] = [\n    \"amount\": %normalizedAmount // This works!\n]\n```\n\nThe custom `%` prefix operator transforms any `Int`, `Double`, `String`, `Bool`, `[JSEN]` and `[String:JSEN]` values into its respective JSEN value.\n\nBy design, no support was added to transform `Optional` into a `.null` to prevent misuse.\n\n\u003cdetails\u003e\u003csummary\u003eClick here to expand the reason why it could lead to mistakes\u003c/summary\u003e\n\u003cp\u003e\n\nTo illustrate the possible problems around an `%optionalValue` operation, picture the following scenario:\n\n```swift\nlet request: [String:JSEN] = [\n    \"middle_name\": %optionalString\n]\nnetwork.post(path: \"user\", parameters: request)\nnetwork.put(path: \"user\", parameters: request)\nnetwork.patch(path: \"user\", parameters: request)\nnetwork.mergePatch(path: \"user\", parameters: request)\n```\n\nIn the scenarios above, what do you think should be the RESTful expected behavior?\n\nIf the `%` operator detected a nonnull String, great. But if it detected its underlying value to be `.none` (aka `nil`), it would convert the value to `.null`, which, when encoded, would be converted to `NSNull()` (more on this below in the Codable section). As you imagine, `NSNull()` and `nil` have very different behaviors when it comes to RESTful APIs - the former might delete the key information on the database, while the latter will simply be ignored by Swift Dictionary (as if the field wasn't even there).\n\nHence, if you want to use an optional value, make the call explicit by using either `.null` if you know the value must be encoded into a `NSNull()` instance, or unwrap its value and wrap it around one of the non-null JSEN cases.\n\n\u003c/p\u003e\n\u003c/details\u003e\n\n### Conformance to Codable\n\nOf course! We couldn't miss this. JSEN has native support to `Encodable \u0026 Decodable` (aka `Codable`), so you can easily parse JSEN to/from JSON-like structures. Each case is mapped to its respective value type, and `.null` maps to a `NSNull()` instance (which, in a JSON, is represented by `null`).\n\nOne additional utility was added as well, which's the `decode(as:)` function. It receives a Decodable-conformant Type as parameter and will attempt to decode the JSEN value into the given type using a two-pass strategy:\n- First, it encodes the JSEN to `Data`, and attempts to decode that `Data` into the given type.\n- If that fails and the JSEN is a `.string(…)` case, it attempts to encode the JSEN's string using `.utf8`. If it is able to encode it, it attempts to decode the resulting `Data` into the given type.\n\n### Subscript Using KeyPath\n\nLast, but not least, comes the `KeyPath` subscript.\n\nBased on [@olebegemann](https://twitter.com/olebegemann)'s [article](https://oleb.net/blog/2017/01/dictionary-key-paths), `KeyPath` is a simple struct used to represent multiple segments of a string. It is initializable by a string literal such as `\"this.is.a.keypath\"` and, when initialized, the string gets separated by periods, which compounds the struct's segments.\n\nThe subscript to JSEN allows the following syntax:\n\n```swift\nlet request: [String:JSEN] = [\n    \"1st\": [\n        \"2nd\": [\n            \"3rd\": \"Hello!\"\n        ]\n    ]\n]\nprint(request[keyPath: \"1st.2nd.3rd\"]) // \"Hello!\"\n```\n\nWithout this syntax, you'd have to create multiple chains of awkward optionals and unwrap them in weird and verbosy ways to access a nested value in a dictionary. I'm not a fan of doing that :)\n\n# Contributions\n\nIf you spot something wrong, missing, or if you'd like to propose improvements to this project, please open an Issue or a Pull Request with your ideas and I promise to get back to you within 24 hours! 😇\n\n# References\n\nJSEN was heavily based on [Statically-typed JSON payload in Swift](https://jobandtalent.engineering/statically-typed-json-payload-in-swift-bd193a9e8cf2) and other various implementations of this same utility spread throughout Stack Overflow and Swift Forums. I brought everything I needed together in this project because I couldn't find something similar as a Swift Package that had everything I needed.\n\n# License\n\nThis project is open source and covered by a standard 2-clause BSD license. That means you can use (publicly, commercially and privately), modify and distribute this project's content, as long as you mention *Roger Oba* as the original author of this code and reproduce the LICENSE text inside your app, repository, project or research paper.\n\n# Explore my other tools\n\n\u003cimg width=\"400\" alt=\"Statused Social Banner\" src=\"https://statused.com/assets/social-banner.png\"\u003e\n\nForget about 'When did release v2.1.3 go live again?' and 'Is the app ready to be tested yet?'\n\nStatused monitors App Store Connect and send you notifications directly on Slack.\n\nLearn more: [statused.com](https://statused.com?ref=jsen)\n\n# Contact\n\nTwitter: [@rogerluan_](https://twitter.com/rogerluan_)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frogerluan%2Fjsen","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Frogerluan%2Fjsen","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frogerluan%2Fjsen/lists"}