0

当我使用 Postman 访问我的配置 API 时,我得到了以下 json 响应。在此响应中,两个 apiVersion 键是数字而不是字符串。

{
    "data": {
        "availability": {
            "auth": true,
            "ab": true,
            "cd": true
        },
        "helloWorldConfiguration": {
            "apiKey": "abcefg",
            "rootUrl": "https://foo",
            "apiVersion": 3
        },
        "fooBarConfiguration": {
            "baseUrl": "https://foo",
            "apiVersion": 1,
            "privateApiPath": "",
            "publicApiPath": "dev",
            "tokenPath": ""
        }
    },
    "errors": []
}

当我尝试对其进行解码时,它会因typeMismatch错误而失败。当我输出响应的内容时,我看到以下内容对我来说很好。

data = {
    availability = {
        auth = 1;
        ab = 1;
        cd = 1;
    };
    helloWorldConfiguration = {
        apiVersion = 1;
        baseUrl = "https://foo";
        privateApiPath = "";
        publicApiPath = dev;
        tokenPath = "";
    };
    fooBarConfiguration = {
        apiKey = abcefg;
        apiVersion = 3;
        rootUrl = "https://foo";
    };
};
errors =     (
);

给我的错误表明它data.helloWorldConfiguration.apiVersion的类型是字符串而不是 int。从我从 Postman 得到的原始 HTTP 响应中,我们可以看出并非如此。

typeMismatch(Swift.Int, Swift.DecodingError.Context(codingPath: [CodingKeys(stringValue: "data", intValue: nil), CodingKeys(stringValue: "helloWorldConfiguration", intValue: nil), CodingKeys(stringValue: "apiVersion", intValue :nil)],debugDescription:“预期解码 Int,但找到了一个字符串/数据。”,基础错误:nil)) 21:17:40 错误无法将响应数据解码为模型表示。

我的模型将这些属性表示为整数,因此它似乎接收到响应并将这些数字视为字符串,但事实并非如此。

public struct ServerConfiguration: Decodable {
    let availability: AvailabilityConfiguration
    let helloWorldConfiguration: HelloWorldConfiguration
    let fooBarConfiguration: FooBarConfiguration

    init(availability: AvailabilityConfiguration, helloWorldConfiguration: HelloWorldConfiguration, fooBarConfiguration: FloatSinkConfiguration) {
        self.availability = availability
        self.helloWorldConfiguration = helloWorldConfiguration
        self.fooBarConfiguration = fooBarConfiguration
    }
}

public struct FooBarConfiguration: Decodable {
    let baseUrl: String
    let apiVersion: Int
    let privateApiPath: String
    let publicApiPath: String
    let tokenPath: String

    init(baseUrl: String, apiVersion: Int, privateApiPath: String, publicApiPath: String, tokenPath: String) {
        self.baseUrl = baseUrl
        self.apiVersion = apiVersion
        self.privateApiPath = privateApiPath
        self.publicApiPath = publicApiPath
        self.tokenPath = tokenPath
    }
}

public struct AvailabilityConfiguration: Decodable {
    let auth: Bool
    let ab: Bool
    let cd: Bool

    init(auth: Bool, ab: Bool, cd: Bool) {
        self.auth = auth
        self.ab = ab
        self.cd = cd
    }
}

public struct HelloWorldConfiguration: Codable {
    let apiKey: String
    let rootUrl: String
    let apiVersion: Int

    init(apiKey: String, rootUrl: String, apiVersion: Int) {
        self.apiKey = apiKey
        self.rootUrl = rootUrl
        self.apiVersion = apiVersion
    }
}

如您所见,我的apiVersion成员都是整数类型以及 json 响应。我在这里做错了什么?我假设发生的事情是 Swift 正在考虑 json 字符串中的数字,而不管它们在 json 中的实际表示方式。是这样吗?

编辑以显示 Alamofire 响应数据的 utf8 字符串

21:44:06 INFO GET: https:foo/configuration
{
    "data" : {
        "availability" : {
            "auth" : true,
            "ab" : true,
            "cb" : true
        },
        "helloWorldConfiguration" : {
            "apiKey" : "abcd",
            "rootUrl" : "https://foo",
            "apiVersion" : "3"
        },
        "fooBarConfiguration" : {
            "baseUrl" : "https://foo",
            "apiVersion" : "1",
            "privateApiPath" : "",
            "publicApiPath" : "dev",
            "tokenPath" : "auth/token"
        }
    },
    "errors" : []
}

看起来尽管 API 正确地apiVersion以数字形式返回,但 Swift 正在将其转换为字符串。我解码不正确吗?

func getRoute<TResponseData: Decodable>(route:String, completion: @escaping (TResponseData) -> Void) throws {
    let headers = try! self.getHeaders(contentType: ContentType.json)
    let completeUrl: String = self.getUrl(route: route, requestUrl: nil)
    logger.info("GET: \(completeUrl)")
Alamofire.request(
    completeUrl,
    method: .get,
    parameters: nil,
    encoding: JSONEncoding.default,
    headers: headers)
    .validate()
    .responseJSON { (response) -> Void in
        self.logger.info("GET Response: \(String(describing:response.response?.statusCode))")

        switch response.result {
        case .success(_):
            let decoder = JSONDecoder()
            decoder.dateDecodingStrategy = .custom(Date.toFooBarDate)
            do {
                let result = try decoder.decode(TResponseData.self, from: response.data!)
                completion(result)
            } catch DecodingError.dataCorrupted(let error) {
                self.logger.error(error.underlyingError!)
                return
            } catch {
                print(response.result.value!)
                print(error)
                self.logger.error("Unable to decode the response data into a model representation.")
                return
            }
        }
    }
4

1 回答 1

0

我在操场上检查了一下,似乎一切正常。要找到真正的问题,我认为您需要提供从哪里获取 json 的真实 url,并且可以使用 alamofire 检查

import Foundation
let json = """
{
"data": {
    "availability": {
        "auth": true,
        "ab": true,
        "cd": true
    },
    "helloWorldConfiguration": {
        "apiKey": "abcefg",
        "rootUrl": "https://foo",
        "apiVersion": 3
    },
    "fooBarConfiguration": {
        "baseUrl": "https://foo",
        "apiVersion": 1,
        "privateApiPath": "",
        "publicApiPath": "dev",
        "tokenPath": ""
    }
},
"errors": []
 }
 """
let data = json.data(using: .utf8)


struct Response : Codable {
let data : Data?
let errors : [String]?
 }
 struct Availability : Codable {
let auth : Bool?
let ab : Bool?
let cd : Bool?
 }

 struct Data : Codable {
let availability : Availability?
let helloWorldConfiguration : HelloWorldConfiguration?
let fooBarConfiguration : FooBarConfiguration?
 }

struct FooBarConfiguration : Codable {
let baseUrl : String?
let apiVersion : Int?
let privateApiPath : String?
let publicApiPath : String?
let tokenPath : String?
}
struct HelloWorldConfiguration : Codable {
let apiKey : String?
let rootUrl : String?
let apiVersion : Int?
}


 let decoder = JSONDecoder()

 let response = try decoder.decode(Response.self, from: data!)
 print(response)

这是回应

响应(数据:可选(__lldb_expr_11.Data(可用性:可选(__lldb_expr_11.Availability(auth:可选(真),ab:可选(真),cd:可选(真))),helloWorldConfiguration:可选(__lldb_expr_11.HelloWorldConfiguration(apiKey) :可选(“abcefg”),rootUrl:可选(“ https://foo ”),apiVersion:可选(3))),fooBarConfiguration:可选(__lldb_expr_11.FooBarConfiguration(baseUrl:可选(“ https://foo ”) , apiVersion: Optional(1), privateApiPath: Optional(""), publicApiPath: Optional("dev"), tokenPath: Optional(""))))), 错误: Optional([]))

于 2018-08-20T05:55:51.737 回答