У меня есть сетевой уровень, который я использую для вызова нескольких конечных точек.Я хотел бы уменьшить количество повторяющегося кода и подумал, что, возможно, я смогу передать свою модель ответа как часть моей конечной точки.
Идея состоит в том, чтобы вместо необходимости использовать несколько функций, которые просто отличаются по ответу, я мог бы простовызовите мой сетевой уровень и получите этот набор на основе пути.
Текущая ошибка, которую я вижу,
Var 'responseType' не является типом элемента 'IdentityEndpoint'
Я надеялся достичь чего-то подобного
mutating func identity(with endpoint: IdentityEndpoint, completion: @escaping (Either<IdentityEndpoint.responseType>) -> Void)
вместо этого
mutating func identity(with endpoint: IdentityEndpoint, completion: @escaping (Either<OAuthToken>) -> Void)
APIClient
struct APIClient: APIClientProtocol {
var task: URLSessionDataTask = URLSessionDataTask()
var session: SessionProtocol = URLSession.shared
var request: URLRequest?
mutating func identity(with endpoint: IdentityEndpoint, completion: @escaping (Either<IdentityEndpoint.responseType>) -> Void) {
dispatch(endpoint: endpoint, completion: completion)
}
}
extension APIClient {
fileprivate mutating func dispatch<T: Codable>(endpoint: EndpointProtocol, completion: @escaping (Either<T>) -> Void) {
do {
request = try constructRequest(from: endpoint)
guard let request = request else { return }
call(with: request, completion: completion)
} catch {}
}
fileprivate func constructRequest(from route: EndpointProtocol) throws -> URLRequest {
var request = URLRequest(url: route.baseUrl.appendingPathComponent(route.path), cachePolicy: .reloadIgnoringLocalAndRemoteCacheData, timeoutInterval: 10.0)
request.httpMethod = route.httpMethod.rawValue
do {
switch route.task {
case .request(let headers):
addAdditionalHeaders(headers, request: &request)
case .requestParams(let bodyParams, let encoding, let urlParams, let headers):
addAdditionalHeaders(headers, request: &request)
try configureParameters(bodyParams: bodyParams, encoding: encoding, urlParams: urlParams, request: &request)
}
return request
} catch {
throw NSError(domain: "Could not create request task for \(route.task)", code: 0, userInfo: nil)
}
}
fileprivate func configureParameters(bodyParams: Parameters?, encoding: ParameterEncoding, urlParams: Parameters?, request: inout URLRequest) throws {
do {
try encoding.encode(urlRequest: &request, bodyParams: bodyParams, urlParams: urlParams)
} catch {
throw NSError(domain: "Could not configure params for request", code: 0, userInfo: nil)
}
}
fileprivate func addAdditionalHeaders(_ additionalHeaders: HTTPHeaders?, request: inout URLRequest) {
guard let headers = additionalHeaders else { return }
for (key, value) in headers {
request.setValue(value, forHTTPHeaderField: key)
}
}
}
IdentityEndPoint
protocol EndpointProtocol {
var baseUrl: URL { get }
var path: String { get }
var httpMethod: HTTPMethod { get }
var task: HTTPTask { get }
var headers: HTTPHeaders? { get }
}
public enum IdentityEndpoint {
case accessToken(company: String, code: String)
func getDomain(forService service: String) -> URL {
return URL(string: "https://{SERVICE}.foo.bar".replacingOccurrences(of: "{SERVICE}", with: service))!
}
}
extension IdentityEndpoint: EndpointProtocol {
var baseUrl: URL {
return getDomain(forService: "identity")
}
var responseType: Codable {
switch self {
default:
return OAuthToken.self as! Codable
}
}
var path: String {
switch self {
case .accessToken(let props):
return "/auth/realms/\(props.company)/protocol/openid-connect/token"
}
}
var httpMethod: HTTPMethod {
switch self {
case .accessToken:
return .POST
}
}
var headers: HTTPHeaders? {
switch self {
case .accessToken:
return ["Content-Type": "application/x-www-form-urlencoded"]
}
}
var task: HTTPTask {
switch self {
case .accessToken(let props):
return .requestParams(bodyParams: [
"grant_type": "authorization_code", "code": "\(props.code)", "redirect_uri": "homedev://oauth-callback", "client_id": "mobile-home"
], encoding: .jsonEncoding, urlParams: nil, headers: headers)
}
}
}