Converting Codable/Encodable to JSON object swift
Asked Answered
C

2

15

Recently i incorporated Codable in a project and to get a JSON object from a type conforming to Encodable i came up with this extension,

extension Encodable {

    /// Converting object to postable JSON
    func toJSON(_ encoder: JSONEncoder = JSONEncoder()) -> [String: Any] {
        guard let data = try? encoder.encode(self),
              let object = try? JSONSerialization.jsonObject(with: data, options: .allowFragments),
              let json = object as? [String: Any] else { return [:] }
        return json
    }
}

This works well but could there be any better way to achieve the same?

Church answered 22/10, 2018 at 5:26 Comment(5)
Not related but You can combine 3 separate guard condition in one comma separated !!Laylalayman
Why do you need this? Do you use it with alamofire?Spatola
I use it with Alamofire. In some cases it needs to add/remove a key-value from the object's JSON or replace values for some keys while sending without changing the object.Church
You could add a collection [String: Codable] to your object to store keys that can change. Then you will only need JSONEncoder to convert object to json data. Use that data to prepare URLRequest and send it to Alamofire's request method that takes URLRequestConvertible protocolSpatola
The name of the function is misleading. You are going to convert structs to a dictionary via JSON. Never ignore Codable and JSONSerialization errors. Make the function throw, remove the question marks after try and hand over the error to the caller.Arbil
A
29

My suggestion is to name the function toDictionary and hand over possible errors to the caller. A conditional downcast failure (type mismatch) is thrown wrapped in an typeMismatch Decoding error.

extension Encodable {

    /// Converting object to postable dictionary
    func toDictionary(_ encoder: JSONEncoder = JSONEncoder()) throws -> [String: Any] {
        let data = try encoder.encode(self)
        let object = try JSONSerialization.jsonObject(with: data)
        if let json = object as? [String: Any]  { return json }
        
        let context = DecodingError.Context(codingPath: [], debugDescription: "Deserialized object is not a dictionary")
        throw DecodingError.typeMismatch(type(of: object), context)
    }
}
Arbil answered 22/10, 2018 at 7:34 Comment(0)
D
8

Convert encodable object to JSON string using this extension:

extension Encodable {
    /// Converting object to postable JSON
    func toJSON(_ encoder: JSONEncoder = JSONEncoder()) throws -> NSString {
        let data = try encoder.encode(self)
        let result = String(decoding: data, as: UTF8.self)
        return NSString(string: result)
    }
}
Demarcation answered 13/5, 2022 at 8:8 Comment(1)
conversion to NSString is extraVitelline

© 2022 - 2025 — McMap. All rights reserved.