Для моего сетевого модуля у меня есть этот протокол, который я использую для доступа к различным частям API:
protocol Router: URLRequestConvertible {
var baseUrl: URL { get }
var route: Route { get }
var method: HTTPMethod { get }
var headers: [String: String]? { get }
var encoding: ParameterEncoding? { get }
var responseResultType: Decodable.Type? { get }
}
Я принимаю это с перечислениями, которые выглядят так:
enum TestRouter: Router {
case getTestData(byId: Int)
case updateTestData(byId: Int)
var route: Route {
switch self {
case .getTestData(let id): return Route(path: "/testData/\(id)")
case .updateTestData(let id): return Route(path: "/testDataOtherPath/\(id)")
}
}
var method: HTTPMethod {
switch self {
case .getTestData: return .get
case .updateTestData: return .put
}
}
var headers: [String : String]? {
return [:]
}
var encoding: ParameterEncoding? {
return URLEncoding.default
}
var responseResultType: Decodable.Type? {
switch self {
case .getTestData: return TestData.self
case .updateTestData: return ValidationResponse.self
}
}
}
Я хочу использовать Codable
для декодирования вложенных ответов Api. Каждый ответ состоит из токена и результата, содержание которого зависит от маршрута запроса.
Для выполнения запроса я хочу использовать тип, указанный в свойстве responseResultType
в enum
выше.
struct ApiResponse<Result: Decodable>: Decodable {
let token: String
let result: Result
}
extension Router {
func asURLRequest() throws -> URLRequest {
// Construct URL
var completeUrl = baseUrl.appendingPathComponent(route.path, isDirectory: false)
completeUrl = URL(string: completeUrl.absoluteString.removingPercentEncoding ?? "")!
// Create URL Request...
var urlRequest = URLRequest(url: completeUrl)
// ... with Method
urlRequest.httpMethod = method.rawValue
// Add headers
headers?.forEach { urlRequest.addValue($0.value, forHTTPHeaderField: $0.key) }
// Encode URL Request with the parameters
if encoding != nil {
return try encoding!.encode(urlRequest, with: route.parameters)
} else {
return urlRequest
}
}
func requestAndDecode(completion: @escaping (Result?) -> Void) {
NetworkAdapter.sessionManager.request(urlRequest).validate().responseData { response in
let responseObject = try? JSONDecoder().decode(ApiResponse<self.responseResultType!>, from: response.data!)
completion(responseObject.result)
}
}
}
Но в моем методе requestAndDecode
Выдает ошибку компилятора (Cannot invoke 'decode' with an argument list of type '(Any.Type, from: Data)'
). Я не могу использовать ApiResponse<self.responseResultType!>
таким образом.
Я мог бы сделать эту функцию универсальной и вызвать ее так:
TestRouter.getTestData(byId: 123).requestAndDecode(TestData.self, completion:)
но тогда мне придется передавать тип ответа каждый раз, когда я хочу использовать эту конечную точку.
Я хочу добиться, чтобы функция расширения requestAndDecode
брала информацию о типе ответа из себя, свойство responseResultType
.
Возможно ли это?