Code Monkey home page Code Monkey logo

Comments (6)

zoul avatar zoul commented on August 28, 2024 1

Other than that, querying a JSON value like this is an example use case of the new dynamic member lookup feature in Swift, see SE-0195.

from generic-json-swift.

zoul avatar zoul commented on August 28, 2024

To be honest I did not give much thought to the use case of working with the resulting JSON object manually, my use case was mostly storage or automated postprocessing. But:

if
    let value = subject["value"] as? [String : Any],
    let identities = value["identities"] as? [[String : Any]],
    let types: [String] = identities.compactMap({ $0["type"] as? String }) { … }

This already assumes some kind of structure on the incoming data. Would it be possible to model this structure using Codable?

struct Value: Codable {
    struct TypeTag: Codable { … } // Maybe only use the generic JSON type here?
    struct Identity: Codable {
        let types: [TypeTag]
    }
    let identities: [Identity]
}

from generic-json-swift.

cjmconie avatar cjmconie commented on August 28, 2024

That's a great link. I hadn't even thought of SE-0195 as being able to address this issue. Though, we do have to wait until Swift 4.2 for it...

In the mean time, extrapolating from Example Usage, by adding an extension to JSON:

extension JSON {
    
    public var stringValue: String? {
        if case .string(let value) = self {
            return value
        }
        return nil
    }
    
    public var floatValue: Float? {
        if case .number(let value) = self {
            return value
        }
        return nil
    }
    
    public var boolValue: Bool? {
        if case .bool(let value) = self {
            return value
        }
        return nil
    }
    
    public var objectValue: [String : JSON]? {
        if case .object(let value) = self {
            return value
        }
        return nil
    }
    
    public var arrayValue: [JSON]? {
        if case .array(let value) = self {
            return value
        }
        return nil
    }
    
    public var isNull: Bool {
        if case .null = self {
            return true
        }
        return false
    }
    
    public subscript(index: Int) -> JSON? {
        if case .array(let arr) = self {
            return index < arr.count ? arr[index] : nil
        }
        return nil
    }
    
    public subscript(key: String) -> JSON? {
        if case .object(let dict) = self {
            return dict[key]
        }
        return nil
    }
    
}

Extracting "resources" and "types" becomes:

if let resource = genericJSON?["subject"]?["resource"]?.stringValue {
    print("Resource: \(resource)")
}
        
if let types = genericJSON?["subject"]?["value"]?["identities"]?.arrayValue?.compactMap( {$0["type"]?.stringValue } ) {
    print("Types: \(types)")
}

Is this worthy of a PR?


Regarding defining the type to conform to Decodable, this is not possible in my use case. I decode a json payload (where only some of the payload structure is known) into a Struct, and then pass the struct to an API consumer. Only the consumer knows the structure of the "unknown" section. I use the JSON type for this unknown section.

Example

{
  "known1": "some-string",
  "known2": true,
  "known3": 1000,
  "unknown": {
    // some unknown structure
  }
}

from generic-json-swift.

zoul avatar zoul commented on August 28, 2024

I decode a json payload (where only some of the payload structure is known) into a Struct, and then pass the struct to an API consumer. Only the consumer knows the structure of the "unknown" section. I use the JSON type for this unknown section.

I just wonder if something like this makes sense:

extension JSONDecoder {
    func decode<T: Decodable>(_ what: T.Type, from json: JSON) throws -> T {
        let data = try JSONEncoder().encode(json)
        return try JSONDecoder().decode(what, from: data)
    }
}

struct DecodedFirst: Decodable {
    let known1: String
    let known2: String
    let unknown: JSON
}

struct DecodedLater: Decodable {
    let foo: String
}

let json = """
    {
        "known1": "foo",
        "known2": "bar",
        "unknown": {
            "foo": "bar"
        }
    }
"""

let wrapper = try JSONDecoder().decode(DecodedFirst.self, from: Data(json.utf8))
let decoded = try JSONDecoder().decode(DecodedLater.self, from: wrapper.unknown)
print(decoded)

This way you would get both – you could decode the β€œenvelope” first and the unknown part later, both using plain Decodable with its convenience and safety. The re-encoding part is slightly stupid though?

from generic-json-swift.

cjmconie avatar cjmconie commented on August 28, 2024

That's an interesting approach and it certainly addresses the use case.

Though, yes, the series of transformations (data > JSON > data > native type) may be bit cumbersome. I will look into this some more.

For now, I am happy to leave the unknown type as JSON. The addition of query helpers provides an adequate API for the consumer.

Thank you for your assistance.

from generic-json-swift.

zoul avatar zoul commented on August 28, 2024

Happy to help! Thank you for your contributions πŸ‘

from generic-json-swift.

Related Issues (16)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    πŸ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. πŸ“ŠπŸ“ˆπŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❀️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.