Я пытаюсь добавить NULL в качестве значения для ключа в моем httpBody. Но пока разрешено делать только [String : String]
. Я думал об изменении значения String
на Any, но это запускает эффект домино на протяжении всего RestManager. Я хотел быть уверен, что это возможно. Или если бы был другой более интуитивный способ сделать это.
Заранее спасибо.
Мой RestManager:
import Foundation
class RestManager {
var httpBody: Data?
var requestHttpHeaders = RestEntity()
var urlQueryParameters = RestEntity()
var httpBodyParameters = RestEntity()
private func addURLQueryParameters(toURL url: URL) -> URL {
if urlQueryParameters.totalItems() > 0 {
guard var urlComponents = URLComponents(url: url, resolvingAgainstBaseURL: false) else { return url }
var queryItems = [URLQueryItem]()
for (key, value) in urlQueryParameters.allValues() {
let item = URLQueryItem(name: key, value: value.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed))
queryItems.append(item)
}
urlComponents.queryItems = queryItems
guard let updatedURL = urlComponents.url else { return url }
return updatedURL
}
return url
}
private func getHttpBody() -> Data? {
guard let contentType = requestHttpHeaders.value(forkey: "Content-Type") else { return nil }
if contentType.contains("application/json") {
return try? JSONSerialization.data(withJSONObject: httpBodyParameters.allValues(), options: [.prettyPrinted, .sortedKeys])
} else {
return httpBody
}
}
private func prepareRequest(withUrl url: URL?, httpBody: Data?, httpMethod: HTTPMethod) -> URLRequest? {
guard let url = url else { return nil }
var request = URLRequest(url: url)
request.httpMethod = httpMethod.rawValue
for (header, value) in requestHttpHeaders.allValues() {
request.setValue(value, forHTTPHeaderField: header)
}
request.httpBody = httpBody
return request
}
func makeRequest(toURL url: URL, withHttpMethod httpMethod: HTTPMethod, completion: @escaping (_ result: Results) -> Void) {
DispatchQueue.global(qos: .userInitiated).async { [weak self] in
let targetURL = self?.addURLQueryParameters(toURL: url)
let httpBody = self?.getHttpBody()
guard let request = self?.prepareRequest(withUrl: targetURL, httpBody: httpBody, httpMethod: httpMethod) else {
completion(Results(withError: CustomError.failedToCreateRequest))
return
}
let sessionConfiguration = URLSessionConfiguration.default
let session = URLSession(configuration: sessionConfiguration)
let task = session.dataTask(with: request) {(data, response, error) in
completion(Results(withData: data,
response: Response(fromURLResponse: response),
error: error))
}
task.resume()
}
}
func getData(fromURL url: URL, completion: @escaping (_ data: Data?) -> Void) {
DispatchQueue.global(qos: .userInitiated).async {
let sessionConfiguration = URLSessionConfiguration.default
let session = URLSession(configuration: sessionConfiguration)
let task = session.dataTask(with: url, completionHandler: { (data, response, error) in
guard let data = data else { completion(nil); return }
completion(data)
})
task.resume()
}
}
}
extension RestManager {
enum HTTPMethod: String {
case get
case post
case put
case patch
case delete
}
enum CustomError: Error {
case failedToCreateRequest
}
struct RestEntity {
private var values: [String: String] = [ : ]
mutating func add(value: String, forkey key: String) {
values[key] = value
}
func value(forkey key: String) -> String? {
return values[key]
}
func allValues() -> [String : String] {
return values
}
func totalItems() -> Int {
return values.count
}
}
struct Response {
var response: URLResponse?
var httpStatusCode: Int = 0
var headers = RestEntity()
init(fromURLResponse response: URLResponse?) {
guard let response = response else { return }
self.response = response
httpStatusCode = (response as? HTTPURLResponse)?.statusCode ?? 0
if let headerFields = (response as? HTTPURLResponse)?.allHeaderFields {
for (key, value) in headerFields {
headers.add(value: "\(value)", forkey: "\(key)")
}
}
}
}
struct Results {
var data: Data?
var response: Response?
var error: Error?
init(withData data: Data?, response: Response?, error: Error?) {
self.data = data
self.response = response
self.error = error
}
init(withError error: Error?) {
self.error = error
}
}
}
extension RestManager.CustomError: LocalizedError {
public var localizedDescription: String {
switch self {
case .failedToCreateRequest: return NSLocalizedString("Unable to create the URLRequest object.", comment: "")
}
}
}