pushdeer/ios/Prototype_version/Pods/Moya/Sources/Moya/Endpoint.swift
2021-12-23 00:19:55 +08:00

161 lines
7.3 KiB
Swift
Executable File

import Foundation
/// Used for stubbing responses.
public enum EndpointSampleResponse {
/// The network returned a response, including status code and data.
case networkResponse(Int, Data)
/// The network returned response which can be fully customized.
case response(HTTPURLResponse, Data)
/// The network failed to send the request, or failed to retrieve a response (eg a timeout).
case networkError(NSError)
}
/// Class for reifying a target of the `Target` enum unto a concrete `Endpoint`.
/// - Note: As of Moya 11.0.0 Endpoint is no longer generic.
/// Existing code should work as is after removing the generic.
/// See #1529 and #1524 for the discussion.
open class Endpoint {
public typealias SampleResponseClosure = () -> EndpointSampleResponse
/// A string representation of the URL for the request.
public let url: String
/// A closure responsible for returning an `EndpointSampleResponse`.
public let sampleResponseClosure: SampleResponseClosure
/// The HTTP method for the request.
public let method: Moya.Method
/// The `Task` for the request.
public let task: Task
/// The HTTP header fields for the request.
public let httpHeaderFields: [String: String]?
public init(url: String,
sampleResponseClosure: @escaping SampleResponseClosure,
method: Moya.Method,
task: Task,
httpHeaderFields: [String: String]?) {
self.url = url
self.sampleResponseClosure = sampleResponseClosure
self.method = method
self.task = task
self.httpHeaderFields = httpHeaderFields
}
/// Convenience method for creating a new `Endpoint` with the same properties as the receiver, but with added HTTP header fields.
open func adding(newHTTPHeaderFields: [String: String]) -> Endpoint {
Endpoint(url: url, sampleResponseClosure: sampleResponseClosure, method: method, task: task, httpHeaderFields: add(httpHeaderFields: newHTTPHeaderFields))
}
/// Convenience method for creating a new `Endpoint` with the same properties as the receiver, but with replaced `task` parameter.
open func replacing(task: Task) -> Endpoint {
Endpoint(url: url, sampleResponseClosure: sampleResponseClosure, method: method, task: task, httpHeaderFields: httpHeaderFields)
}
fileprivate func add(httpHeaderFields headers: [String: String]?) -> [String: String]? {
guard let unwrappedHeaders = headers, unwrappedHeaders.isEmpty == false else {
return self.httpHeaderFields
}
var newHTTPHeaderFields = self.httpHeaderFields ?? [:]
unwrappedHeaders.forEach { key, value in
newHTTPHeaderFields[key] = value
}
return newHTTPHeaderFields
}
}
/// Extension for converting an `Endpoint` into a `URLRequest`.
public extension Endpoint {
// swiftlint:disable cyclomatic_complexity
/// Returns the `Endpoint` converted to a `URLRequest` if valid. Throws an error otherwise.
func urlRequest() throws -> URLRequest {
guard let requestURL = Foundation.URL(string: url) else {
throw MoyaError.requestMapping(url)
}
var request = URLRequest(url: requestURL)
request.httpMethod = method.rawValue
request.allHTTPHeaderFields = httpHeaderFields
switch task {
case .requestPlain, .uploadFile, .uploadMultipart, .downloadDestination:
return request
case .requestData(let data):
request.httpBody = data
return request
case let .requestJSONEncodable(encodable):
return try request.encoded(encodable: encodable)
case let .requestCustomJSONEncodable(encodable, encoder: encoder):
return try request.encoded(encodable: encodable, encoder: encoder)
case let .requestParameters(parameters, parameterEncoding):
return try request.encoded(parameters: parameters, parameterEncoding: parameterEncoding)
case let .uploadCompositeMultipart(_, urlParameters):
let parameterEncoding = URLEncoding(destination: .queryString)
return try request.encoded(parameters: urlParameters, parameterEncoding: parameterEncoding)
case let .downloadParameters(parameters, parameterEncoding, _):
return try request.encoded(parameters: parameters, parameterEncoding: parameterEncoding)
case let .requestCompositeData(bodyData: bodyData, urlParameters: urlParameters):
request.httpBody = bodyData
let parameterEncoding = URLEncoding(destination: .queryString)
return try request.encoded(parameters: urlParameters, parameterEncoding: parameterEncoding)
case let .requestCompositeParameters(bodyParameters: bodyParameters, bodyEncoding: bodyParameterEncoding, urlParameters: urlParameters):
if let bodyParameterEncoding = bodyParameterEncoding as? URLEncoding, bodyParameterEncoding.destination != .httpBody {
fatalError("Only URLEncoding that `bodyEncoding` accepts is URLEncoding.httpBody. Others like `default`, `queryString` or `methodDependent` are prohibited - if you want to use them, add your parameters to `urlParameters` instead.")
}
let bodyfulRequest = try request.encoded(parameters: bodyParameters, parameterEncoding: bodyParameterEncoding)
let urlEncoding = URLEncoding(destination: .queryString)
return try bodyfulRequest.encoded(parameters: urlParameters, parameterEncoding: urlEncoding)
}
}
// swiftlint:enable cyclomatic_complexity
}
/// Required for using `Endpoint` as a key type in a `Dictionary`.
extension Endpoint: Equatable, Hashable {
public func hash(into hasher: inout Hasher) {
switch task {
case let .uploadFile(file):
hasher.combine(file)
case let .uploadMultipart(multipartData), let .uploadCompositeMultipart(multipartData, _):
hasher.combine(multipartData)
default:
break
}
if let request = try? urlRequest() {
hasher.combine(request)
} else {
hasher.combine(url)
}
}
/// Note: If both Endpoints fail to produce a URLRequest the comparison will
/// fall back to comparing each Endpoint's hashValue.
public static func == (lhs: Endpoint, rhs: Endpoint) -> Bool {
let areEndpointsEqualInAdditionalProperties: Bool = {
switch (lhs.task, rhs.task) {
case (let .uploadFile(file1), let .uploadFile(file2)):
return file1 == file2
case (let .uploadMultipart(multipartData1), let .uploadMultipart(multipartData2)),
(let .uploadCompositeMultipart(multipartData1, _), let .uploadCompositeMultipart(multipartData2, _)):
return multipartData1 == multipartData2
default:
return true
}
}()
let lhsRequest = try? lhs.urlRequest()
let rhsRequest = try? rhs.urlRequest()
if lhsRequest != nil, rhsRequest == nil { return false }
if lhsRequest == nil, rhsRequest != nil { return false }
if lhsRequest == nil, rhsRequest == nil { return lhs.hashValue == rhs.hashValue && areEndpointsEqualInAdditionalProperties }
return lhsRequest == rhsRequest && areEndpointsEqualInAdditionalProperties
}
}