问题描述
当 API 返回文本(字符串)http 状态代码 200
时,我需要知道什么是最佳实践或最佳方法但它也为 http 状态码 400
返回 json 对象我有使用原生 URLSession 构建的网络层,并使用 JSONDecoder 来解析 JSON
因此,在调用该函数时,它采用通用参数,例如[Product](产品数组)对象,它将为我们提供产品数组
我的问题是,API 的结构或制作是经过良好实践的,以及使用 swift ios 解析 json 的最佳实践是什么
已编辑 - 附加信息
假设您有 api 端点 base_url/api/v1/get-otp-code 并且您正在发布您的电话号码:
Method: POST
url: base_url/api/v1/get-otp-code
params: { "phone": "123456789" }
如果您之前确实请求过 OTP,则此端点将返回 json 值
回复:{"error":"some error","message": "some message"}
但是如果您是第一次请求,它将为您提供字符串值
回复:"dwaotpwaadd-dadwaawwdcwdadodwde"
所以如果你不知道什么类型会返回,你应该让它动态
解决方法
嗨@nikakirkitadze,欢迎来到我们的社区!
正如您所知,每个请求都可能带有错误,因此您也必须在通用方法中处理这些错误。
假设您有以下通用方法来执行获取请求:
func getRequest<T: Codable,U: Codable>(completion: @escaping(_ response: T?,_ error: HTTPClientError<U>?) -> Void) {
URLSession.shared.dataTask(with: URLRequest(url: URL(string: "")!)) { (data,response,error) in
guard let statusCode = (response as? HTTPURLResponse)?.statusCode,let data = data else {
completion(nil,HTTPClientError(type: .invalidResponse,model: nil))
return
}
if statusCode == 400 {
let decodedErrorData = try? JSONDecoder().decode(U.self,from: data)
completion(nil,HTTPClientError(statusCode: statusCode,type: .AUTH_FAILED,model: decodedErrorData))
return
}
// Success
do {
let decodedData = try JSONDecoder().decode(T.self,from: data)
completion(decodedData,nil)
} catch {
print(error)
let decodedErrorData = try? JSONDecoder().decode(U.self,type: .parsingError,model: decodedErrorData))
}
}.resume()
}
ExampleResponse 模型和通用 HTTPClientError:
struct ExampleResponse: Codable {
// Add your coding keys here..
}
public final class HTTPClientError<T: Codable>: Error {
public let statusCode: Int?
public let type: Code
public let model: T?
public enum Code: Int {
case none
case invalidResponse
case invalidRequest
case parsingError
case AUTH_FAILED = 401
case FAILED = 500
case SERVICE_UNAVAILABLE = 501
}
public required init(statusCode: Int? = nil,type: Code,model: T? = nil) {
self.statusCode = statusCode
self.type = type
self.model = model
}
}
如您所见,我们使用通用类型作为编码类型创建了一个通用错误。
现在你可以像这样调用你的方法:
func getExampleResponse(completion: @escaping(_ response: ExampleResponse?,_ error: HTTPClientError<String>?) -> Void) {
getRequest(completion: completion)
}
因此,关于您的请求和您正在等待的错误,您可以调整泛型类型以满足您的需求。
这里的最佳做法是:
- 使用 Swift Codables 来映射您的回复
- 始终检查是否有错误
- 创建通用方法以避免重复代码
您可以查看我关于网络的轻量级 swift 包以获取更多帮助:https://github.com/kstefanou52/SKHTTPClient
更新未知响应类型
如果您不知道响应的类型,则必须尝试转换响应,如下所示:
func getRequest(completion: @escaping(_ response: String?,_ error: [String: String]?) -> Void) {
URLSession.shared.dataTask(with: URLRequest(url: URL(string: "")!)) { (data,["error": "empty response"])
return
}
if let stringResponse = String(data: data,encoding: .utf8) {
completion(stringResponse,nil)
} else if let dictionaryResponse = try? JSONDecoder().decode([String: String].self,from: data) {
completion(nil,dictionaryResponse)
} else {
completion(nil,["error": "unknown response"])
}
}.resume()
}