Dogs API decoding JSON

Hi there!

I am trying to develop a small app, where I am working with API calls and JSON. The API I am working with is this: dogs API where I am trying to get list of all dogs. You can also see the JSON there.

I have been able make a GET request from the API and in Proxyman I can see that I am getting 200 OK and I can also see the JSONs structure of all the dogs. So, it means I am getting the data I should and now I need to parse them. Here’s where I got stuck and I couldn’t find a way out yet. Also here is the snip from the proxy man where you can see the JSON’s structure:

{
  "message": {
    "affenpinscher": [],
    "african": [],
    "airedale": [],
    "akita": [],
    "appenzeller": [],
    "australian": [
      "shepherd"
    ],
    "basenji": [],
    "beagle": [],
    "bluetick": [],
    "borzoi": [],
    "bouvier": [],
    "boxer": [],
    "brabancon": [],
    "briard": [],
    "buhund": [
      "norwegian"
    ],
    "bulldog": [
      "boston",
      "english",
      "french"
    ],
    "bullterrier": [
      "staffordshire"
    ],
    "cattledog": [
      "australian"
    ],
    "chihuahua": [],
    "chow": [],
    "clumber": [],
    "cockapoo": [],
    "collie": [
      "border"
    ],
    "coonhound": [],
    "corgi": [
      "cardigan"
    ],
    "cotondetulear": [],
    "dachshund": [],
    "dalmatian": [],
    "dane": [
      "great"
    ],
    "deerhound": [
      "scottish"
    ],
    "dhole": [],
    "dingo": [],
    "doberman": [],
    "elkhound": [
      "norwegian"
    ],
    "entlebucher": [],
    "eskimo": [],
    "finnish": [
      "lapphund"
    ],
    "frise": [
      "bichon"
    ],
    "germanshepherd": [],
    "greyhound": [
      "italian"
    ],
    "groenendael": [],
    "havanese": [],
    "hound": [
      "afghan",
      "basset",
      "blood",
      "english",
      "ibizan",
      "plott",
      "walker"
    ],
    "husky": [],
    "keeshond": [],
    "kelpie": [],
    "komondor": [],
    "kuvasz": [],
    "labradoodle": [],
    "labrador": [],
    "leonberg": [],
    "lhasa": [],
    "malamute": [],
    "malinois": [],
    "maltese": [],
    "mastiff": [
      "bull",
      "english",
      "tibetan"
    ],
    "mexicanhairless": [],
    "mix": [],
    "mountain": [
      "bernese",
      "swiss"
    ],
    "newfoundland": [],
    "otterhound": [],
    "ovcharka": [
      "caucasian"
    ],
    "papillon": [],
    "pekinese": [],
    "pembroke": [],
    "pinscher": [
      "miniature"
    ],
    "pitbull": [],
    "pointer": [
      "german",
      "germanlonghair"
    ],
    "pomeranian": [],
    "poodle": [
      "miniature",
      "standard",
      "toy"
    ],
    "pug": [],
    "puggle": [],
    "pyrenees": [],
    "redbone": [],
    "retriever": [
      "chesapeake",
      "curly",
      "flatcoated",
      "golden"
    ],
    "ridgeback": [
      "rhodesian"
    ],
    "rottweiler": [],
    "saluki": [],
    "samoyed": [],
    "schipperke": [],
    "schnauzer": [
      "giant",
      "miniature"
    ],
    "setter": [
      "english",
      "gordon",
      "irish"
    ],
    "sheepdog": [
      "english",
      "shetland"
    ],
    "shiba": [],
    "shihtzu": [],
    "spaniel": [
      "blenheim",
      "brittany",
      "cocker",
      "irish",
      "japanese",
      "sussex",
      "welsh"
    ],
    "springer": [
      "english"
    ],
    "stbernard": [],
    "terrier": [
      "american",
      "australian",
      "bedlington",
      "border",
      "cairn",
      "dandie",
      "fox",
      "irish",
      "kerryblue",
      "lakeland",
      "norfolk",
      "norwich",
      "patterdale",
      "russell",
      "scottish",
      "sealyham",
      "silky",
      "tibetan",
      "toy",
      "welsh",
      "westhighland",
      "wheaten",
      "yorkshire"
    ],
    "tervuren": [],
    "vizsla": [],
    "waterdog": [
      "spanish"
    ],
    "weimaraner": [],
    "whippet": [],
    "wolfhound": [
      "irish"
    ]
  },
  "status": "success"
}

As a reference project I am using the last project from iOS foundation where we connect to Yel’s API.
That’s why the structure of the project is almost the same.

Here is my Dog.swift class:

import Foundation

class Dog: Decodable {
    
    var message: Message?
    var status: String?
}

struct Message: Decodable {
    var affenpinscher: [String]?
    var african: [String]?
    var airedale: [String]?
    var akita: [String]?
    var appenzeller: [String]?
    var australian: [String]?
    var basenji: [String]?
    var beagle: [String]?
    var bluetick: [String]?
    var borzoi: [String]?
    var bouvier: [String]?
    var boxer: [String]?
    var brabancon: [String]?
    var briard: [String]?
    var buhund: [String]?
    var bulldog: [String]?
    var bullterrier: [String]?
    var cattledog: [String]?
    var chihuahua: [String]?
    var chow: [String]?
    var clumber: [String]?
    var cockapoo: [String]?
    var collie: [String]?
    var coonhound: [String]?
    var corgi: [String]?
    var contondetulear: [String]?
    var dachshund: [String]?
    var dalmatian: [String]?
    var dane: [String]?
    var deerhound: [String]?
    var dhole: [String]?
    var dingo: [String]?
    var doberman: [String]?
    var elkhound: [String]?
    var entlebucher: [String]?
    var eskimo: [String]?
    var finnish: [String]?
    var frise: [String]?
    var germanshepherd: [String]?
    var greyhound: [String]?
    var groenendael: [String]?
    var havanese: [String]?
    var hound: [String]?
    var husky: [String]?
    var keeshond: [String]?
    var kelpie: [String]?
    var komondor: [String]?
    var kuvasz: [String]?
    var labradoodle: [String]?
    var labrador: [String]?
    var leonberg: [String]?
    var lhasa: [String]?
    var malamute: [String]?
    var malinois: [String]?
    var maltese: [String]?
    var mastiff: [String]?
    var mexicanhairless: [String]?
    var mix: [String]?
    var mountain: [String]?
    var newfoundland: [String]?
    var otterhound: [String]?
    var ovcharka: [String]?
    var papillon: [String]?
    var pekinese: [String]?
    var pembroke: [String]?
    var pinscher: [String]?
    var pitbull: [String]?
    var pointer: [String]?
    var pomeranian: [String]?
    var poodle: [String]?
    var pug: [String]?
    var puggle: [String]?
    var pyrenees: [String]?
    var redbone: [String]?
    var retriever: [String]?
    var ridgeback: [String]?
    var rottweiler: [String]?
    var saluki: [String]?
    var samoyed: [String]?
    var schipperke: [String]?
    var schnauzer: [String]?
    var setter: [String]?
    var sheepdog: [String]?
    var shiba: [String]?
    var shihtzu: [String]?
    var spaniel: [String]?
    var springer: [String]?
    var stbernard: [String]?
    var terrier: [String]?
    var tervuren: [String]?
    var vizsla: [String]?
    var waterdog: [String]?
    var weimaraner: [String]?
    var whippet: [String]?
    var wolfhound: [String]?
}

I did as well the DogSearch struct as we did in the project:

import Foundation

struct DogSearch: Decodable {
    
    var message = Message()
    var status = ""
    
}

And here is my ContentModel class:

import Foundation

class ContentModel: ObservableObject {
    
    @Published var dogs = [DogSearch]()
    
    init() {
        getDogs()
    }
    
    func getDogs(){
        
        // Create URL
        let urlString = "https://dog.ceo/api/breeds/list/all"
        let url = URL(string: urlString)
        
        if let url = url {
            // Create URL request
            var request = URLRequest(url: url, cachePolicy: .reloadIgnoringLocalCacheData, timeoutInterval: 10)
            request.httpMethod = "GET"
             
            // Get URLSession
            let session = URLSession.shared
            
            // Create Data Task
            let dataTask = session.dataTask(with: request) { (data, response, error) in
                // Check that there is not an error
                if error == nil {
                    
                    do {
                        // Parse JSON
                        let decoder = JSONDecoder()
                        let result = try decoder.decode(DogSearch.self, from: data!)
                        print(result)
                        
                        // Assign result to the dogs property
//                        DispatchQueue.main.async {
//                            self.dogs = result.message
//                        }
                    } catch {
                        print(error)
                    }
                }
            }
            
            // Start the Data Task
            dataTask.resume()
        }
    }
    
}

The thing is that until that point when I print the result from the ContentModel class I can see in my console in Xcode the data from the JSON:

Optional(["italian"]), groenendael: Optional([]), havanese: Optional([]), hound: Optional(["afghan", "basset", "blood", "english", "ibizan", "plott", "walker"]), husky: Optional([]), keeshond: Optional([]), kelpie: Optional([]), komondor: Optional([]), kuvasz: Optional([]), labradoodle: Optional([]), labrador: Optional([]), leonberg: Optional([]), lhasa: Optional([]), malamute: Optional([]), malinois: Optional([]), maltese: Optional([]), mastiff: Optional(["bull", "english", "tibetan"]), mexicanhairless: Optional([]), mix: Optional([]), mountain: Optional(["bernese", "swiss"]), newfoundland: Optional([]), otterhound: Optional([]), ovcharka: Optional(["caucasian"]), papillon: Optional([]), pekinese: Optional([]), pembroke: Optional([]), pinscher: Optional(["miniature"]), pitbull: Optional([]), pointer: Optional(["german", "germanlonghair"]), pomeranian: Optional([]), poodle: Optional(["miniature", "standard", "toy"]), pug: Optional([]), puggle: Optional([]), pyrenees: Optional([]), redbone: Optional([]), retriever: Optional(["chesapeake", "curly", "flatcoated", "golden"]), ridgeback: Optional(["rhodesian"]), rottweiler: Optional([]), saluki: Optional([]), samoyed: Optional([]), schipperke: Optional([]), schnauzer: Optional(["giant", "miniature"]), setter: Optional(["english", "gordon", "irish"]), sheepdog: Optional(["english", "shetland"]), shiba: Optional([]), shihtzu: Optional([]), spaniel: Optional(["blenheim", "brittany", "cocker", "irish", "japanese", "sussex", "welsh"]), springer: Optional(["english"]), stbernard: Optional([]), terrier: Optional(["american", "australian", "bedlington", "border", "cairn", "dandie", "fox", "irish", "kerryblue", "lakeland", "norfolk", "norwich", "patterdale", "russell", "scottish", "sealyham", "silky", "tibetan", "toy", "welsh", "westhighland", "wheaten", "yorkshire"]), tervuren: Optional([]), vizsla: Optional([]), waterdog: Optional(["spanish"]), weimaraner: Optional([]), whippet: Optional([]), wolfhound: Optional(["irish"])), status: "success")

But what I cannot do is assign this result to dogs variable. I think the problem is that I am parsing the JSON incorrectly. That in my Dog class or DogSearch struct the structure of JSON is not identical to the Dog JSON from the API. Because message is object of other arrays and I am not sure if I am therefore rewriting the JSON correctly or not.

Sorry, for such a long message. I just don’t know how else I could explain the problem. I hope it makes at least a bit of sense and I also hope there is someone who can help me with that, because it would mean a lot for me!

Thanks in advance guys,
Have a nice weekend,
Cheers.

No you’re parsing it correctly, otherwise you wouldn’t see all the “optional….” Being printed

You can add a breakpoint at that line to see if it’s decoded by properly

dogs is an array of DogSearch When it should be a Message object, did the error message say something similar to that? That you’re trying to set a variable but it’s not the proper type?

This is if you set it this way: self.dogs = result.message

1 Like

Thanks it helped my problem I really do appreciate it!

I have another issue I cam across, but I think I will post it in a new tread, so it is more clear since a lot of things changed.

Yes please put it in a new thread! It helps keep things organized and others to find solutions

1 Like

I did it already :slight_smile: Hope you’ll have time to look at it.

1 Like