I'm using Moya Swift framework for networking layer which is constructed on top of Alamofire.
Currently, I'm trying to send request with URL encoded parameters that have same keys.
i.e. http://some-site/request?param=v1¶m=v2¶m=v3
I've already tried to group these params into Set or NSSet or Array like this but nothing helps to achieve desired result.
["param": ["v1", "v2", "v3"]];
["param": Set(arrayLiteral: "v1", "v2", "v3")]
Any help would be appreciated either with Moya or with Alamofire itself.
Edit: Here is some sample code to give basic idea:
Api Router setup
import Moya
// MARK:- Enum Declaration
enum ApiRouter {
case XAuth(login: String, password: String)
case SomeRequest(params: [String])
}
// MARK:- Moya Path
extension ApiRouter: MoyaPath {
var path: String {
switch self {
case .XAuth:
return "/authorization"
case .SomeRequest:
return "/some-request"
}
}
}
// MARK:- Moya Target
extension ApiRouter: MoyaTarget {
private var base: String {
return "http://some-site"
}
var baseURL: NSURL {
return NSURL(string: base)!
}
var parameters: [String: AnyObject] {
switch self {
case .XAuth(let login, let password):
return [
"email": login,
"password": password
]
case .SomeRequest(let params):
return [
"params": params
]
}
var method: Moya.Method {
switch self {
case .XAuth:
return .POST
case .SomeRequest,
return .GET
}
}
var sampleData: NSData {
switch self {
case .XAuth:
return "{}".dataUsingEncoding(NSUTF8StringEncoding)
case .ServiceRequests:
return "{}".dataUsingEncoding(NSUTF8StringEncoding)
}
}
}
Api Provider setup
let endpointsClosure = { (target: ApiRouter) -> Endpoint<ApiRouter> in
let endpoint = Endpoint<ApiRouter>(
URL: target.baseURL.URLByAppendingPathComponent(target.path).absoluteString!,
sampleResponse: EndpointSampleResponse.Success(200, { target.sampleData }),
method: target.method,
parameters: target.parameters,
parameterEncoding: parameterEncoding(target)
)
switch target {
case .XAuth:
return endpoint
default:
let token = "some-token"
return endpoint.endpointByAddingHTTPHeaderFields(["Authorization": "Bearer: \(token)"])
}
}
func parameterEncoding(target: ApiRouter) -> Moya.ParameterEncoding {
switch target {
case .XAuth:
return .JSON
case .SomeRequest:
return .URL
}
}
let apiProvider = MoyaProvider(endpointsClosure: endpointsClosure)
apiProvider.request(ApiRouter.SomeRequest(params: ["v1", "v2", "v3"], completion: { (data, statusCode, response, error) in
/* ... */
})
Thanks.
So I found a solution which is actually pretty simple and obvious. Reading Alamofire's documentation I found this:
Since there is no published specification for how to encode collection types, Alamofire follows the convention of appending [] to the key for array values (foo[]=1&foo[]=2), and appending the key surrounded by square brackets for nested dictionary values (foo[bar]=baz).
So, for this cases there's Custom ParameterEncoding option which takes closure where you can actually specify your own implementation of how you want parameters to be formed.
Here's the same question with the same answer.
Moya is a good idea, but I actually feel that with some thinking, we can construct a network abstraction layer using Swift without much code.
Our goal is :
Here is what I ended up with on a dummy project :
public class API {
public static let baseURL: String = "http://colourlovers.com/api"
public enum Endpoints {
case Colors(String)
case Palettes(String)
case Patterns(String)
public var method: Alamofire.Method {
switch self {
case .Colors,
.Palettes,
.Patterns:
return Alamofire.Method.GET
}
}
public var path: String {
switch self {
case .Colors:
return baseURL+"/colors"
case .Palettes:
return baseURL+"/palettes"
case .Patterns:
return baseURL+"/patterns"
}
}
public var parameters: [String : AnyObject] {
var parameters = ["format":"json"]
switch self {
case .Colors(let keywords):
parameters["keywords"] = keywords
break
case .Palettes(let keywords):
parameters["keywords"] = keywords
break
case .Patterns(let keywords):
parameters["keywords"] = keywords
break
}
return parameters
}
}
public static func request(
endpoint: API.Endpoints,
completionHandler: Response<AnyObject, NSError> -> Void)
-> Request {
let request = Manager.sharedInstance.request(
endpoint.method,
endpoint.path,
parameters: endpoint.parameters,
encoding: .URL,
headers: nil
).responseJSON { response in
if (response.result.error) != nil {
DDLogError("\n<----\n" + response.result.error!.description)
completionHandler(response)
} else {
DDLogInfo("\n<----\n" + response.response!.description)
completionHandler(response)
}
}
DDLogInfo("\n---->\n" + request.description)
return request
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With