Swift/AlamoFire:无法解码 JSON 响应

Swift/AlamoFire: Unable to decode JSON response

我正在尝试使用 AlamoFire and decode them using the built-in .responseDecodable handler 发出请求。我到达的 API 端点是 https://api.linode.com/v4/regions.

Request.swift:

import Foundation
import Alamofire

func getRegions() {
        
    AF.request("https://api.linode.com/v4/regions")
        .validate()
        .responseDecodable(of: Region.self) { (response) in
            guard let regions = response.value else { return }
            print(regions)
            debugPrint("Response: \(response)")
        }
    
}

当我构建和 运行 二进制文件并调用 getRegions() 时,我在控制台中没有输出(调试或其他)。当我像这样更改 getRegions() 并删除 .responseDecodable 时,我在控制台中得到了原始的 JSON:

    let regionRequest = AF.request("https://api.linode.com/v4/regions")
    regionRequest.responseJSON { (data) in
        print(data)

这是我的区域模型:

Region.swift:

import Foundation

struct Region: Decodable {
    
    enum resolvers: String, Decodable {
        case ipv4, ipv6
    }
    
    let capabilities: Array<String>
    let country: String
    let id: String
    let resolvers: Set<resolvers>
    let status: String
    let page: Int
    let pages: Int
    let results: Int
    
    enum CodingKeys: String, CodingKey {
        
        case capabilities
        case country
        case resolvers
        case status
        case id
        case page
        case pages
        case results
        
    }
    
}

这是 API 的 JSON 响应:

data =     (
                {
            capabilities =             (
                Linodes,
                NodeBalancers,
                "Block Storage",
                "GPU Linodes",
                Kubernetes,
                "Cloud Firewall",
                Vlans
            );
            country = in;
            id = "ap-west";
            resolvers =             {
                ipv4 = "172.105.34.5,172.105.35.5,172.105.36.5,172.105.37.5,172.105.38.5,172.105.39.5,172.105.40.5,172.105.41.5,172.105.42.5,172.105.43.5";
                ipv6 = "2400:8904::f03c:91ff:fea5:659,2400:8904::f03c:91ff:fea5:9282,2400:8904::f03c:91ff:fea5:b9b3,2400:8904::f03c:91ff:fea5:925a,2400:8904::f03c:91ff:fea5:22cb,2400:8904::f03c:91ff:fea5:227a,2400:8904::f03c:91ff:fea5:924c,2400:8904::f03c:91ff:fea5:f7e2,2400:8904::f03c:91ff:fea5:2205,2400:8904::f03c:91ff:fea5:9207";
            };
            status = ok;
        },
                {
            capabilities =             (
                Linodes,
                NodeBalancers,
                "Block Storage",
                Kubernetes,
                "Cloud Firewall",
                Vlans
            );
            country = ca;
            id = "ca-central";
            resolvers =             {
                ipv4 = "172.105.0.5,172.105.3.5,172.105.4.5,172.105.5.5,172.105.6.5,172.105.7.5,172.105.8.5,172.105.9.5,172.105.10.5,172.105.11.5";
                ipv6 = "2600:3c04::f03c:91ff:fea9:f63,2600:3c04::f03c:91ff:fea9:f6d,2600:3c04::f03c:91ff:fea9:f80,2600:3c04::f03c:91ff:fea9:f0f,2600:3c04::f03c:91ff:fea9:f99,2600:3c04::f03c:91ff:fea9:fbd,2600:3c04::f03c:91ff:fea9:fdd,2600:3c04::f03c:91ff:fea9:fe2,2600:3c04::f03c:91ff:fea9:f68,2600:3c04::f03c:91ff:fea9:f4a";
            };
            status = ok;
        },
                {
            capabilities =             (
                Linodes,
                NodeBalancers,
                "Block Storage",
                Kubernetes,
                "Cloud Firewall",
                Vlans
            );
            country = au;
            id = "ap-southeast";
            resolvers =             {
                ipv4 = "172.105.166.5,172.105.169.5,172.105.168.5,172.105.172.5,172.105.162.5,172.105.170.5,172.105.167.5,172.105.171.5,172.105.181.5,172.105.161.5";
                ipv6 = "2400:8907::f03c:92ff:fe6e:ec8,2400:8907::f03c:92ff:fe6e:98e4,2400:8907::f03c:92ff:fe6e:1c58,2400:8907::f03c:92ff:fe6e:c299,2400:8907::f03c:92ff:fe6e:c210,2400:8907::f03c:92ff:fe6e:c219,2400:8907::f03c:92ff:fe6e:1c5c,2400:8907::f03c:92ff:fe6e:c24e,2400:8907::f03c:92ff:fe6e:e6b,2400:8907::f03c:92ff:fe6e:e3d";
            };
            status = ok;
        },
                {
            capabilities =             (
                Linodes,
                NodeBalancers,
                "Block Storage",
                Kubernetes,
                "Cloud Firewall"
            );
            country = us;
            id = "us-central";
            resolvers =             {
                ipv4 = "72.14.179.5,72.14.188.5,173.255.199.5,66.228.53.5,96.126.122.5,96.126.124.5,96.126.127.5,198.58.107.5,198.58.111.5,23.239.24.5";
                ipv6 = "2600:3c00::2,2600:3c00::9,2600:3c00::7,2600:3c00::5,2600:3c00::3,2600:3c00::8,2600:3c00::6,2600:3c00::4,2600:3c00::c,2600:3c00::b";
            };
            status = ok;
        },
                {
            capabilities =             (
                Linodes,
                NodeBalancers,
                "Block Storage",
                Kubernetes,
                "Cloud Firewall"
            );
            country = us;
            id = "us-west";
            resolvers =             {
                ipv4 = "173.230.145.5,173.230.147.5,173.230.155.5,173.255.212.5,173.255.219.5,173.255.241.5,173.255.243.5,173.255.244.5,74.207.241.5,74.207.242.5";
                ipv6 = "2600:3c01::2,2600:3c01::9,2600:3c01::5,2600:3c01::7,2600:3c01::3,2600:3c01::8,2600:3c01::4,2600:3c01::b,2600:3c01::c,2600:3c01::6";
            };
            status = ok;
        },
                {
            capabilities =             (
                Linodes,
                NodeBalancers,
                "Cloud Firewall",
                Vlans
            );
            country = us;
            id = "us-southeast";
            resolvers =             {
                ipv4 = "74.207.231.5,173.230.128.5,173.230.129.5,173.230.136.5,173.230.140.5,66.228.59.5,66.228.62.5,50.116.35.5,50.116.41.5,23.239.18.5";
                ipv6 = "2600:3c02::3,2600:3c02::5,2600:3c02::4,2600:3c02::6,2600:3c02::c,2600:3c02::7,2600:3c02::2,2600:3c02::9,2600:3c02::8,2600:3c02::b";
            };
            status = ok;
        },
                {
            capabilities =             (
                Linodes,
                NodeBalancers,
                "Block Storage",
                "Object Storage",
                "GPU Linodes",
                Kubernetes
            );
            country = us;
            id = "us-east";
            resolvers =             {
                ipv4 = "66.228.42.5,96.126.106.5,50.116.53.5,50.116.58.5,50.116.61.5,50.116.62.5,66.175.211.5,97.107.133.4,207.192.69.4,207.192.69.5";
                ipv6 = "2600:3c03::7,2600:3c03::4,2600:3c03::9,2600:3c03::6,2600:3c03::3,2600:3c03::c,2600:3c03::5,2600:3c03::b,2600:3c03::2,2600:3c03::8";
            };
            status = ok;
        },
                {
            capabilities =             (
                Linodes,
                NodeBalancers,
                "Block Storage",
                Kubernetes,
                "Cloud Firewall"
            );
            country = uk;
            id = "eu-west";
            resolvers =             {
                ipv4 = "178.79.182.5,176.58.107.5,176.58.116.5,176.58.121.5,151.236.220.5,212.71.252.5,212.71.253.5,109.74.192.20,109.74.193.20,109.74.194.20";
                ipv6 = "2a01:7e00::9,2a01:7e00::3,2a01:7e00::c,2a01:7e00::5,2a01:7e00::6,2a01:7e00::8,2a01:7e00::b,2a01:7e00::4,2a01:7e00::7,2a01:7e00::2";
            };
            status = ok;
        },
                {
            capabilities =             (
                Linodes,
                NodeBalancers,
                "Block Storage",
                "Object Storage",
                "GPU Linodes",
                Kubernetes
            );
            country = sg;
            id = "ap-south";
            resolvers =             {
                ipv4 = "139.162.11.5,139.162.13.5,139.162.14.5,139.162.15.5,139.162.16.5,139.162.21.5,139.162.27.5,103.3.60.18,103.3.60.19,103.3.60.20";
                ipv6 = "2400:8901::5,2400:8901::4,2400:8901::b,2400:8901::3,2400:8901::9,2400:8901::2,2400:8901::8,2400:8901::7,2400:8901::c,2400:8901::6";
            };
            status = ok;
        },
                {
            capabilities =             (
                Linodes,
                NodeBalancers,
                "Block Storage",
                "Object Storage",
                "GPU Linodes",
                Kubernetes
            );
            country = de;
            id = "eu-central";
            resolvers =             {
                ipv4 = "139.162.130.5,139.162.131.5,139.162.132.5,139.162.133.5,139.162.134.5,139.162.135.5,139.162.136.5,139.162.137.5,139.162.138.5,139.162.139.5";
                ipv6 = "2a01:7e01::5,2a01:7e01::9,2a01:7e01::7,2a01:7e01::c,2a01:7e01::2,2a01:7e01::4,2a01:7e01::3,2a01:7e01::6,2a01:7e01::b,2a01:7e01::8";
            };
            status = ok;
        },
                {
            capabilities =             (
                Linodes,
                NodeBalancers,
                "Block Storage",
                Kubernetes
            );
            country = jp;
            id = "ap-northeast";
            resolvers =             {
                ipv4 = "139.162.66.5,139.162.67.5,139.162.68.5,139.162.69.5,139.162.70.5,139.162.71.5,139.162.72.5,139.162.73.5,139.162.74.5,139.162.75.5";
                ipv6 = "2400:8902::3,2400:8902::6,2400:8902::c,2400:8902::4,2400:8902::2,2400:8902::8,2400:8902::7,2400:8902::5,2400:8902::b,2400:8902::9";
            };
            status = ok;
        }
    );
    page = 1;
    pages = 1;
    results = 11;
})

我在这里做错了什么?我怀疑它与 Region 结构有关,但我一直无法弄清楚。任何帮助将不胜感激,谢谢!

更新:

我稍微简化了我的 Region 模型并添加了选项:

struct Data: Codable {
    
    let data: [Region]
    let page, pages, results: Int
    
}
struct Region: Codable {
    
    let capabilities: [String]?
    let country, id: String?
    let status: String?
    let resolvers: Resolvers?
    
    enum CodingKeys: String, CodingKey {
        case country
        case id
        case status
        case capabilities
        case resolvers
    }
}

struct Resolvers: Codable {
    let ipv4, ipv6: String
}

我现在使用 AlamoFire 得到了成功的响应(虽然一切都是 nil – 进步了!):

success(.Region(capabilities: nil, country: nil, id: nil, status: nil, resolvers: nil))

您可以使用(https://apps.apple.com/us/app/paste-json-as-code-quicktype/id1330801220?mt=12) App Store 中的这个应用程序来解析和解码json,然后您可以使用alamofire 请求并以jsonString 作为响应并解码您的 json 回复。 quickType 为您的数据结构提供自定义 json 解码器,您可以像这样解码您的 reponseString(您的 responseString 中的数据):

do {
   let json = try Data.init(data)
}
catch let err {
   print(err.localizedDescription)
}

感谢所有评论的人!我能够通过添加丢失的编码密钥来解决这个问题。我创建了 Regions.swift,它看起来像这样:

import Foundation

struct Regions: Decodable {
    
    let all: [Region]
    
    enum CodingKeys: String, CodingKey {
        case all = "data"
    }
}

API 响应封装在 data 中。一旦我添加了这个编码密钥,我就能够得到我正在寻找的解码响应:

   AF.request("https://api.linode.com/v4/regions")
         .validate()
        .responseDecodable(of: Regions.self) {(response) in
            guard let regions = response.value else {return}
            print(regions.all[0].self)
        }

回复:

Region(capabilities: ["Linodes", "NodeBalancers", "Block Storage", "GPU Linodes", "Kubernetes", "Cloud Firewall", "Vlans"], country: "in", id: "ap-west", status: "ok", resolvers: QuickCloud.Resolvers(ipv4: "172.105.34.5,172.105.35.5,172.105.36.5,172.105.37.5,172.105.38.5,172.105.39.5,172.105.40.5,172.105.41.5,172.105.42.5,172.105.43.5", ipv6: "2400:8904::f03c:91ff:fea5:659,2400:8904::f03c:91ff:fea5:9282,2400:8904::f03c:91ff:fea5:b9b3,2400:8904::f03c:91ff:fea5:925a,2400:8904::f03c:91ff:fea5:22cb,2400:8904::f03c:91ff:fea5:227a,2400:8904::f03c:91ff:fea5:924c,2400:8904::f03c:91ff:fea5:f7e2,2400:8904::f03c:91ff:fea5:2205,2400:8904::f03c:91ff:fea5:9207"))