Добавьте значение NULL в запрос httpBody Post - REST API - Swift - PullRequest
0 голосов
/ 06 февраля 2020

Я пытаюсь добавить 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: "")
    }
}
}

1 Ответ

0 голосов
/ 06 февраля 2020

Сначала вам нужен словарь с типом значения, который может содержать ваше значение. Тип AnyObject не может иметь значение nil. Таким образом, словарь типа [String: AnyObject] не может иметь значение nil.

Если у вас был словарь с типом значения, который был необязательным типом , например [String: AnyObject?] , тогда он может содержать нулевые значения. Например,

let x : [String : AnyObject?] = ["foo" : nil]

или

x["foo"] = nil as AnyObject?
...