jsonswiftcodable

In Swift5 with Codable, easily handle json key that begins with a dollar sign such as "$date"


In json (particularly from Azure/c# -ish clouds) you will often see,

                "Length": 0,
                "TestDate": {
                    "$date": "2023-09-20T05:00:00.0000000Z"
                },
                "Weight": 0,
                "Height": 0,

This works,

    struct DollarDate: Codable {
        let date: Date
        
        private enum CodingKeys: String, CodingKey {
            case date = "$date"
        }
    }

however, with Swift these days it's usually not necessary to fuss with coding keys.

For example, if a key is a Swift keyword, you can just ...

struct Draft: Codable {
    
    let id: String
    var `case`: Case?   // no problem these days, just use backtick
}

Is there a similar instant solution to problem key names like " $date " in json?


Solution

  • I gather that your question is whether you could do something equivalent to:

    struct Foo {
        let `$bar`: Int          // “Cannot declare entity named '$bar'; the '$' prefix is reserved for implicitly-synthesized declarations”
    }
    

    The short answer is, no, you cannot. We cannot define a property name that starts with a dollar sign, even with the use of backticks. Backticks are simply intended for property identifiers that conflict with a Swift reserved word.

    Regarding the use of the leading dollar sign, see The Swift Programming Language: Lexical Structure: Identifiers. Specifically, the leading $ has a unique purpose in Swift and is explicitly prohibited when declaring our own identifiers. As the aforementioned documentation says:

    The compiler synthesizes identifiers that begin with a dollar sign ($) for properties that have a property wrapper projection. Your code can interact with these identifiers, but you can’t declare identifiers with that prefix.


    CodingKeys is the right way to map a JSON key to something that is syntactically valid in a Swift codebase, such as mapping $date to date.

    We would also use CodingKeys, more generally, any time we want to map JSON keys to any identifier, even if it is just for stylistic consistency. Looking at your JSON, we would likely map JSON keys Length, Width, Height, and TestDate to Swift identifiers length, width, height, and testDate, because in Swift, identifiers that start with uppercase letters are, as a matter of convention, reserved for names of types (e.g., classes, structs, protocols, enumerations, etc.). We would use CodingKeys to map these JSON keys to their lowercased property names, as well as mapping $date to date.


    If this is your own backend, you might want to reconsider both $date as well as those key names that start with uppercase letters. Personally, in my backends, I stick with either camel-case (e.g. testDate) or snake-case (e.g., test_date) as those are two common conventions that are generally consumed naturally by most clients (and, in the case of Swift, eliminates the use of CodingKeys). If you do use snake-case, you can set the decoder’s keyDecodingStrategy to .convertFromSnakeCase, so that it automatically maps the snake-case JSON keys to standard Swift identifiers in camel-case.