Moya/Alamofire-URL закодированные парамы с одинаковыми ключами
Я использую Moya Swift framework для сетевого слоя, который построен поверх Alamofire.
В настоящее время я пытаюсь отправить запрос с URL-кодированными параметрами, которые имеют те же ключи.
То есть http://some-site/request?param=v1¶m=v2¶m=v3
Я уже пытался сгруппировать эти парамы в Set или NSSet или Array, как это, но ничто не помогает достичь желаемого результата.
["param": ["v1", "v2", "v3"]];
["param": Set(arrayLiteral: "v1", "v2", "v3")]
Любая помощь будет оценена либо с Мойей, либо с Аламофайром сам.
Редактировать: ниже приведен пример кода, чтобы дать основную идею:
Настройка маршрутизатора Api
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
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
/* ... */
})
Спасибо.
3 ответа:
Таким образом, я нашел решение, которое на самом деле довольно простое и очевидное. Читая документацию Alamofire , я нашел следующее:
Поскольку нет опубликованной спецификации для кодирования типов коллекций, Alamofire следует соглашению о добавлении [] к ключу для значений массива (foo[]=1&foo[]=2) и добавлении ключа, окруженного квадратными скобками для вложенных значений словаря (foo[bar]=baz).
Итак, для этого случая есть обычай ParameterEncoding опция, которая принимает закрытие, где вы можете фактически указать свою собственную реализацию того, как вы хотите, чтобы параметры были сформированы.
Здесь тот же вопрос с тем же ответом.
Moya-хорошая идея, но я действительно чувствую, что при некотором мышлении мы можем построить сетевой абстрактный слой с помощью Swift без большого количества кода.
Наша цель:
- гибкость, позволяющая эффективно редактировать или добавлять новые конечные точки
- читаемость, чтобы иметь хорошее представление о том, как работает наш API с первого взгляда
- безопасность кода, с типизированными параметрами, позволяющими получить все преимущества предварительной компиляции (завершение, проверка), которые мы ожидаем от Xcode.
- легкая отладка, что означает возможность вставлять журналы до и после веб-запросов
Вот что я получил в результате работы над фиктивным проектом :
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 } }
Вы можете просто создать строку, используя формат, и передать ее в виде запроса URL:
Http://some-site/request?param=v1¶m=v2¶m=v3
String url: String = String(format: "http://some-site/request?param=%@¶m=%@¶m=%@", v1, v2, v3)
Надеюсь, это поможет!