Moya/Alamofire-URL закодированные парамы с одинаковыми ключами


Я использую Moya Swift framework для сетевого слоя, который построен поверх Alamofire.

В настоящее время я пытаюсь отправить запрос с URL-кодированными параметрами, которые имеют те же ключи.

То есть http://some-site/request?param=v1&param=v2&param=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 5

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&param=v2&param=v3

String url: String = String(format: "http://some-site/request?param=%@&param=%@&param=%@", v1, v2, v3)

Надеюсь, это поможет!