0

Let's assume we have a JSON structure as following:

    {
    "July": [
        {
        ...
            "startDate": "July 10",
            "endDate": "July 11",
        ...
        },
        {
            ...
        },
        {
            ...
        },
        {
            ...
        }
    ]
}

I am trying to parse this API with the following struct, using only native swift.

struct Listing: Codable {
    let months: [Month]


    enum CodingKeys: String, CodingKey {
        case months = "June" //here we need all months for the whole year.
    }

}

struct Month: Codable {
    ...
    let startDate: String
    let endDate: String
    ...

    enum CodingKeys: String, CodingKey {
        ...
    }
}

The problem is that the API will return per request every time a new JSON response with a new month thus I need a couple of "CodingKeys" cases: "July", "August" etc, in the same time the Month struct is reusable. There was an idea to solve the issue mapping the entity, though I guess there can be a more elegant solution. Please let me know if you have any ideas how to simplify the solution.

5
  • 1
    This is not an answer to the question but i think the API should return an Array of "months" and every month should have a "name" = "July" ... Correct me if i am wrong here. Commented Jun 24, 2018 at 15:48
  • unfortunately, this API doesn't work like that. As stated before, per each req(providing passing the requested month,year etc.) it returns only the current array for the month requested, in a separate json "file". Commented Jun 24, 2018 at 15:53
  • In your ideal result, where would you want to store "July"? Would it be a key on Month or would Listing.months be a dictionary mapping month to Month? Do you actually care about the word "July" since you have the startDate/endDate? Or would you rather throw away the "July" level? Commented Jun 24, 2018 at 15:53
  • Also, you've marked these Codable. Do you really need to encode them? You have many more options if you make this only Decodable. Commented Jun 24, 2018 at 15:58
  • I think it is fine to throw away the "July" word. Good point. About Codable though, I may need to encode them for future releases. Commented Jun 24, 2018 at 16:27

1 Answer 1

1

First of all if you are going only to decode the JSON adopt only Decodable.

I recommend to decode monthsas dictionary [String:[Month]]

struct Listing: Decodable {
    let months: [String:[Month]]
}

Then get the Month array just by the known month key.

Or use an enum

enum MonthName : String, Decodable  {
    private enum CodingKeys : String, CodingKey { case january = "January", february = "February", ... december = "December" }
    case January, February, ... December
}

struct Listing: Decodable {
    let months: [MonthName:[Month]]
}

Edit:

You can also write a custom initializer to extract the Month array, it assumes that there is only one dictionary with one key-value pair in the root object.

struct Listing: Decodable {

    let months: [Month]

    init(from decoder: Decoder) throws {
        let container = try decoder.singleValueContainer()
        let monthData = try container.decode([String:[Month]].self)
        months = monthData[monthData.keys.first!]!
    }
}
Sign up to request clarification or add additional context in comments.

3 Comments

don't forget about the naming conventions case january = "January", february = "February", ... december = "December"
in this case I will have to provide the keys, which is not really necessary for this application.. Is there any solution which will just ignore whatever is at the top of the JSON tree ( in our case "July") and will decode the rest?
this is exactly what I was trying to get. 4 lines of code instead of modifying a lot . Thank you very much.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.