1

I get some JSON objects from my api that look like this:

{
    "from": "1970-01-01",
    "until": null,
    "employeeId": "13",
    "project": {
        "id": "05c6adce-20cd-4ca3-9eff-8fd430f63a20",
        "version": 0,
        "name": "AGFA",
        "code": "AGFA",
        "start": "2016-01-01",
        "end": "2016-12-31",
        "alternativeCodes": []
    }
},

And I want to use the different parts of it in my program. I did some research and came up with this solution:

import SwiftUI
import CryptoKit

struct Project: Decodable {
    let id: String
    let version: Int
    let name: String
    let code: String
    let start: Date
    let end: Date
    let alternativeCode: [String]
}

struct AssignedProject: Decodable{
    let from: Date
    let until: Date
    let emloyeeId: Int
    let project: Project
}



struct FetchWebsiteView: View {
@Binding var apiKey : String
@State var assignedProjects = [AssignedProject]()
var body: some View {     
    VStack{
        
    }.onAppear{
        Task {
           var x = await doHTTPProjectsCall(token: apiKey)                                
        }
    }
}

func doHTTPProjectsCall(token:String) async -> Array<String> {
    let url = "http://localhost:8160/api/v1/project/assignments/13"
    guard let reqUrl = URL(string: url) else {
        print("Invalid URL")
        return(Array())
    }
    var req = URLRequest(url: reqUrl)
    req.httpMethod = "GET"
    req.setValue("CC0001", forHTTPHeaderField: "CC-Tenant")
    req.setValue("BE", forHTTPHeaderField: "CC-Product")
    
    let task = URLSession.shared.dataTask(with: req) { data, response, error in
        if let data = data {
            let decoder = JSONDecoder()
            decoder.dateDecodingStrategy = .iso8601

            print("Program goes fine till here")

            if let decodedResponse = try?
                decoder.decode([AssignedProject].self, from: data) {

                print("Not doing this too")

                DispatchQueue.main.async {
                    self.assignedProjects = decodedResponse
                    print("Not doing this")
                }
                return
                }
        } else if let error = error {
            print("HTTP Request Failed \(error)") // not printing any errors
        }
        if let response = response as? HTTPURLResponse {
                print("Response HTTP Status code: \(response.statusCode)") // but doing this fine and returning with status code 200 OK
            }
    }
    task.resume()
    
    
    return ["Internship", "Project2", "Test"]
}
}

Since it's not printing any errors and answering with status code 200 OK, i assume the request is fine but I have a problem decoding the JSON object. Thanks in advance

Joakim Danielson
  • 43,251
  • 5
  • 22
  • 52
Pjaks
  • 251
  • 1
  • 11
  • 2
    Remove that `try?` and use a proper do/catch block. But looking at your `AssignedProject` struct and your example JSON it seems there is an error with `until` property – burnsi Jul 15 '22 at 13:17
  • 1
    Never use `try?` (with a question mark) unless you know how to debug. Use a proper `do`/`try`/`catch` and print the error thrown. Currently, you are just ignoring the parsing thrown error while it could tell you exactly why it failed the parsing... – Larme Jul 15 '22 at 13:22
  • @burnsi and Larme) thanks for the advice, i am going to try again and tell the results – Pjaks Jul 15 '22 at 13:24
  • @burnsi I fixed it and now it seems like it's working. The only problem left is like you mentioned that type error. Now I get following error: "dataCorrupted(Swift.DecodingError.Context(codingPath: [_JSONKey(stringValue: "Index 0", intValue: 0), CodingKeys(stringValue: "from", intValue: nil)], debugDescription: "Expected date string to be ISO8601-formatted.", underlyingError: nil))" any idea how to fix this? – Pjaks Jul 15 '22 at 13:29
  • 1
    You need to set a [date decoding strategy](https://developer.apple.com/documentation/foundation/jsondecoder/2895216-datedecodingstrategy) for your decoder. The date format used in [this question](https://stackoverflow.com/questions/49343500/cant-decode-date-in-swift-4) is different but you should get a good idea on how to proceed from it. – Joakim Danielson Jul 15 '22 at 13:37
  • Change the Dates to Strings, until should be optional. – lorem ipsum Jul 15 '22 at 13:41
  • 1
    I now see that you actually have one set already :), well you need a custom formatter for your date format. – Joakim Danielson Jul 15 '22 at 13:42

1 Answers1

1

There is a lot going on with the structs you try to decode to. You got several typos in here. E.g. alternativeCode instead of alternativeCodes...

Next there are several type mismatches here. For example employeeId is a String and not an Int.

Next the dates need a custom dateformatter to be decoded succesfully.

struct Project: Decodable {
    let id: String
    let version: Int
    let name: String
    let code: String
    let start: Date
    let end: Date
    let alternativeCodes: [String]
}

struct AssignedProject: Decodable{
    let from: Date
    let until: Date?
    let employeeId: String
    let project: Project
}


let formatter = DateFormatter()
formatter.dateFormat = "yyyy-MM-dd"
let decoder = JSONDecoder()
decoder.dateDecodingStrategy = .formatted(formatter)
let result = try decoder.decode([AssignedProject].self, from: data)
burnsi
  • 6,194
  • 13
  • 17
  • 27