I have method writing in Alamofire 3 with customParameterEncoding. This custom encoding just replaces \"[]=\" with \"=\" in queryString and returns it.
Alamofire
In Alamofire 4.0 you should use ParameterEncoding
.
struct CustomEncoding: ParameterEncoding {
func encode(_ urlRequest: URLRequestConvertible, with parameters: Parameters?) throws -> URLRequest {
var request = try! URLEncoding().encode(urlRequest, with: parameters)
let urlString = request.url?.absoluteString.replacingOccurrences(of: "%5B%5D=", with: "=")
request.url = URL(string: urlString!)
return request
}
}
Just separating structs for GET and POST also works.
http://matsue.github.io/post/how-to-remove-square-brackets-with-alamofire/
Alamofire 4 with Swift 3
// Remove square brackets for GET request struct CustomGetEncoding: ParameterEncoding { func encode(_ urlRequest: URLRequestConvertible, with parameters: Parameters?) throws -> URLRequest { var request = try URLEncoding().encode(urlRequest, with: parameters) request.url = URL(string: request.url!.absoluteString.replacingOccurrences(of: "%5B%5D=", with: "=")) return request } } // Remove square brackets for POST request struct CustomPostEncoding: ParameterEncoding { func encode(_ urlRequest: URLRequestConvertible, with parameters: Parameters?) throws -> URLRequest { var request = try URLEncoding().encode(urlRequest, with: parameters) let httpBody = NSString(data: request.httpBody!, encoding: String.Encoding.utf8.rawValue)! request.httpBody = httpBody.replacingOccurrences(of: "%5B%5D=", with: "=").data(using: .utf8) return request } } // Use structs for requests Alamofire.request("http://example.com", method: .get, parameters: ["foo": ["bar1", "bar2"]], encoding: CustomGetEncoding()) Alamofire.request("http://example.com", method: .post, parameters: ["foo": ["bar1", "bar2"]], encoding: CustomPostEncoding())
Looks like a bug by design in Alamofire: https://github.com/Alamofire/Alamofire/issues/329
This is my solution in Swift3 with both get & post method:
extension NSNumber {
fileprivate var isBool: Bool {
return CFBooleanGetTypeID() == CFGetTypeID(self)
}
}
struct CustomEncoding: ParameterEncoding {
fileprivate func escape(_ string: String) -> String {
let generalDelimitersToEncode = ":#[]@" // does not include "?" or "/" due to RFC 3986 - Section 3.4
let subDelimitersToEncode = "!$&'()*+,;="
var allowedCharacterSet = CharacterSet.urlQueryAllowed
allowedCharacterSet.remove(charactersIn: "\(generalDelimitersToEncode)\(subDelimitersToEncode)")
var escaped = ""
if #available(iOS 8.3, *) {
escaped = string.addingPercentEncoding(withAllowedCharacters: allowedCharacterSet) ?? string
} else {
let batchSize = 50
var index = string.startIndex
while index != string.endIndex {
let startIndex = index
let endIndex = string.index(index, offsetBy: batchSize, limitedBy: string.endIndex) ?? string.endIndex
let range = startIndex..<endIndex
let substring = string.substring(with: range)
escaped += substring.addingPercentEncoding(withAllowedCharacters: allowedCharacterSet) ?? substring
index = endIndex
}
}
return escaped
}
fileprivate func queryComponents(fromKey key: String, value: Any) -> [(String, String)] {
var components: [(String, String)] = []
if let dictionary = value as? [String: Any] {
for (nestedKey, value) in dictionary {
components += queryComponents(fromKey: "\(key)[\(nestedKey)]", value: value)
}
} else if let array = value as? [Any] {
for value in array {
components += queryComponents(fromKey: "\(key)[]", value: value)
}
} else if let value = value as? NSNumber {
if value.isBool {
components.append((escape(key), escape((value.boolValue ? "1" : "0"))))
} else {
components.append((escape(key), escape("\(value)")))
}
} else if let bool = value as? Bool {
components.append((escape(key), escape((bool ? "1" : "0"))))
} else {
components.append((escape(key), escape("\(value)")))
}
return components
}
fileprivate func query(_ parameters: [String: Any]) -> String {
var components: [(String, String)] = []
for key in parameters.keys.sorted(by: <) {
let value = parameters[key]!
components += queryComponents(fromKey: key, value: value)
}
return components.map { "\($0)=\($1)" }.joined(separator: "&")
}
func encode(_ urlRequest: URLRequestConvertible, with parameters: Parameters?) throws -> URLRequest {
var request: URLRequest = try urlRequest.asURLRequest()
guard let parameters = parameters else { return request }
guard let mutableRequest = (request as NSURLRequest).mutableCopy() as? NSMutableURLRequest else {
// Handle the error
return request
}
if request.urlRequest?.httpMethod == "GET" {
mutableRequest.url = URL(string: (mutableRequest.url?.absoluteString.replacingOccurrences(of: "%5B%5D=", with: "="))!)
}
if request.urlRequest?.httpMethod == "POST" {
mutableRequest.httpBody = query(parameters).data(using: .utf8, allowLossyConversion: false)
if mutableRequest.httpBody != nil {
let httpBody = NSString(data: mutableRequest.httpBody!, encoding: String.Encoding.utf8.rawValue)!
mutableRequest.httpBody = httpBody.replacingOccurrences(of: "%5B%5D=", with: "=").data(using: String.Encoding.utf8)
}
}
request = mutableRequest as URLRequest
return request
}
}
then send request:
let request = Alamofire.request(URLString, method: method, parameters: parameters, encoding: CustomEncoding(), headers: headers)
request.responseData(queue: self.netWorkQueue) { (response) in
//......//
}