Search code examples
jsonswiftgravatar

Parsing Gravatar Profile JSON in Swift


I am properly loading up my own profile information in an iOS Swift application, but the JSON has an object associated with it which is confusing me on how to properly parse it in order to access the data within it. Here is my method.

func attemptToLoadProfile(hash: String) {
    let url = "https://www.gravatar.com/\(hash).json"
    let fileURL = URL(string: url)
    do {
        let contents = try String(contentsOf: fileURL!)
        let data = contents.data(using: String.Encoding.utf8)
        let json = try? JSONSerialization.jsonObject(with: data!, options: [])
        print(json!)

    } catch {
        print("error parsing json")
    }
}

This works fine, but when I print it out, the JSON is formatted like this.

{
entry =     (
            {
        displayName = edolecki;
        hash = <myhash here>;
        id = 1333520;
        name =             {
            familyName = Dolecki;
            formatted = "Eric Dolecki";
            givenName = Eric;
        };
        photos =             (
                            {
                type = thumbnail;
                value = "https://secure.gravatar.com/avatar/<myhash here>";
            }
        );
        preferredUsername = edolecki;
        profileUrl = "http://gravatar.com/edolecki";
        requestHash = <myhash here>;
        thumbnailUrl = "https://secure.gravatar.com/avatar/<myhash here>";
        urls =             (
        );
    }
);

}

How do I parse the JSON seeing there is that entry object at the root? I am after displayName, id, etc. I normally parse JSON without a more simplified root. I haven't seen this before.


Solution

  • The value associated with the entry key is just an array with one element. In this case, you can access json["entry"], cast it to a [[String: Any]] and access the first element [0]. Then you can access the things you want, like displayName and id.

    A better way to do this is use Codable. Using QuickType, I generated this code:

    struct Root: Codable {
        let entry: [Entry]
    }
    
    struct Entry: Codable {
        let id, hash, requestHash: String
        let profileURL: URL
        let preferredUsername: String
        let thumbnailURL: URL
        let photos: [Photo]
        let displayName: String
    
        enum CodingKeys: String, CodingKey {
            case id, hash, requestHash
            case profileURL = "profileUrl"
            case preferredUsername
            case thumbnailURL = "thumbnailUrl"
            case photos, displayName
        }
    }
    
    struct Photo: Codable {
        let value: URL
        let type: String
    }
    

    Then you can do this to parse the json:

    let decoder = JSONDecoder()
    let root = try decoder.decode(Root.self, from: data)
    // e.g.
    let displayName = root.entry[0].displayName
    

    If you don't need any of the json KVPs, just remove it from the struct.