0

When I call a service (POST) from Postman I get proper JSON:

{
    “XResponse": {
        “xValue1”: “01”,
        “xClearance": null,
        “xValue2”: “02”,
        “xValue3”: “19.95”,
        “xEvents": [
            {
                “x_comment_1": null,
                “x_comment_2”: null
            }
        ],
        “x_id": "0073"
    }
}

But when I call it from my Swift I get: (from print("JSON: (xRaw)”)). It appears to be missing quotes in several places.

{
    XResponse =     {
        “xValue1” = 01;
        xClearance = "<null>";
        “xValue2” = 02;
        “xValue3” = 19.95;
        “xEvents" =         (
                        {
                “x_comment_1" = "<null>";
                “x_comment_2" = "<null>";
            }
        );
        “x_id" = 0073;
    };
})

ViewController.swift

    DataService.shared.fetchX(loc: “00001”){ (result) in
        
        DispatchQueue.main.async {
            switch result {
                case .success(let xRaw):
                    print("JSON: \(xRaw)")

                    }
                    
                case .failure(let error):
                    print(error)
            }
        }
    }
    

DataService.swift

   func fetchX(loc: String, completion: @escaping (Result<Any, Error>) -> Void) {

    var postAuth: String

    let postComponents = createXURLComponents()

    guard let validURL = postComponents.url else {
        print("URL creation failed")
        return
    }

    postAuth = locals.authStringXDEV

    var postRequest = URLRequest(url: validURL, timeoutInterval: Double.infinity)

    let authString = postAuth
    postRequest.addValue("Basic \(authString)", forHTTPHeaderField: "Authorization")
    postRequest.addValue("application/json", forHTTPHeaderField: "Content-Type")
    postRequest.addValue("application/json", forHTTPHeaderField: "Accept")

    let parameters = "{\r\n    \”XRequest\": {\r\n        \”XY_id\": \(loc)\r\n }\r\n}"
    let postData = parameters.data(using: .utf8)

    postRequest.httpMethod = "POST"
    postRequest.httpBody = postData

    URLSession.shared.dataTask(with: postRequest) { data, response, error in

        if let httpResponse = response as? HTTPURLResponse {
            print("getXInfo Response status: \(httpResponse.statusCode)")
        }

        guard let validData = data, error == nil else {
            completion(.failure(error!))
            return
        }

        do {
            let xData = try JSONSerialization.jsonObject(with: validData)
            completion(.success(xData))
         } catch let serializationError {

            print("localizedDescription: \(serializationError.localizedDescription)")
            completion(.failure(serializationError))
        }

    }.resume()

}

Ultimately I would like to return an object which conforms to a struct I have created, but when I try to JSONDecoder().decode I get the following error:

localizedDescription: The data couldn’t be read because it isn’t in the correct format. typeMismatch(Swift.Array, Swift.DecodingError.Context(codingPath: [], debugDescription: "Expected to decode Array but found a dictionary instead.", underlyingError: nil))

I am assuming the error is in the underlying JSON.

Thanks.

Please note that this code is heavily hand-edited.

The struct I have defined is:

import Foundation

struct XResponse: Encodable {
    var xClearance: String?
    var xValue1: String 
    var xValue2: String? 
    var xValue3: String? 
    var x_id: String 
    var xEvents: XX_Events?
    
    enum CodingKeys: String, CodingKey {
        case xValue1, xValue2, xValue3, x_id, xClearance, xEvents
    }

}

extension XResponse: Decodable {
    init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)

        self.xClearance = try container.decodeIfPresent(String.self, forKey: .xClearance)
        self.xValue1 = try container.decode(String.self, forKey: .xValue1)
        self.xValue2 = try container.decodeIfPresent(String.self, forKey: .xValue2 )
        self.x_id = try container.decode(String.self, forKey: .x_id )
        self.xValue3 = try container.decodeIfPresent(String.self, forKey: .xValue3 )
        self.xEvents = try container.decodeIfPresent(XX_Events.self, forKey: .xEvents )
    }
}

struct XX_Events: Encodable {
    var x_comment_1: String? // null,
    var x_comment_2: String? // null,

    enum CodingKeys: String, CodingKey {
        case x_comment_1, x_comment_2
    }
}

extension XX_Events: Decodable {
    init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        self.x_comment_1 = try container.decodeIfPresent(String.self, forKey: .x_comment_1)
        self.x_comment_2 = try container.decodeIfPresent(String.self, forKey: .x_comment_2)
    }
}
Will T
  • 51
  • 1
  • 8
  • 3
    "It appears to be missing quotes in several places." What you printed is a NSDictionary, using the OpenStep format, not a JSON. See the `;` that shouldn't be in a JSON as a item separator? `xData` is a `NSDictionary`. Now, could you show the code with `JSONDecoder()` AND the Codable struct you use too? – Larme Jan 07 '21 at 14:39
  • Does this answer your question? [How to decode a nested JSON struct with Swift Decodable protocol?](https://stackoverflow.com/questions/44549310/how-to-decode-a-nested-json-struct-with-swift-decodable-protocol) – timbre timbre Jan 07 '21 at 15:04
  • Look at the linked answer: since you are getting an object you want nested in "envelop" object, you need to parse it based on "raw response structure", and then get the object you want. – timbre timbre Jan 07 '21 at 15:05

0 Answers0