根据路径更改响应模型/形状



我有一个网络层,我正在使用来调用多个端点。我想减少重复代码的数量,并认为也许我可以将响应模型作为端点的一部分传递。

这个想法是,我不需要多个响应不同的函数,我可以调用我的网络层并根据路径设置这个。

我看到的当前错误是

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)
        }
    }
}

身份端点

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)
        }
    }
}

EndpointProtocol添加associatedtype。然后像这样在IdentityEndpoint中指定它

protocol EndpointProtocol {
    associatedtype ResponseType
    ...
}
extension IdentityEndpoint: EndpointProtocol {
    typealias ResponseType = OAuthToken
    ...
}

现在您将能够编写

mutating func identity(
   with endpoint: IdentityEndpoint,
   completion: @escaping (Either<IdentityEndpoint.ResponseType>) -> Void
)

相关内容

  • 没有找到相关文章

最新更新