Moya/Alamofire - URL 具有相同密钥的编码参数
Moya/Alamofire - URL encoded params with same keys
我正在使用 Moya Swift framework for networking layer which is constructed on top of 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")]
对于 Moya 或 Alamofire 本身的任何帮助,我们将不胜感激。
编辑: 下面是一些示例代码以提供基本概念:
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
/* ... */
})
谢谢。
您可以简单地使用格式创建字符串并将其作为请求传递 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)
希望对您有所帮助!
所以我找到了一个非常简单明了的解决方案。
阅读 Alamofire 的文档我发现了这个:
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).
因此,对于这种情况,有 Custom ParameterEncoding 选项,它会关闭,您可以在其中实际指定您自己的参数实现方式待组建。
Here同样的问题,同样的答案。
Moya是个好主意,但我其实觉得稍微思考一下,我们可以用Swift构建一个网络抽象层,代码不多
我们的目标是:
- 灵活性,能够有效地编辑或添加新端点
- 可读性,一目了然地了解我们的 API 是如何工作的
- 代码安全,类型化参数允许我们期望从 Xcode.
获得的所有预编译优点(完成、验证)
- 易于调试,这意味着能够在网络请求前后插入日志
这是我在 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
}
}
我正在使用 Moya Swift framework for networking layer which is constructed on top of 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")]
对于 Moya 或 Alamofire 本身的任何帮助,我们将不胜感激。
编辑: 下面是一些示例代码以提供基本概念:
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
/* ... */
})
谢谢。
您可以简单地使用格式创建字符串并将其作为请求传递 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)
希望对您有所帮助!
所以我找到了一个非常简单明了的解决方案。 阅读 Alamofire 的文档我发现了这个:
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).
因此,对于这种情况,有 Custom ParameterEncoding 选项,它会关闭,您可以在其中实际指定您自己的参数实现方式待组建。
Here同样的问题,同样的答案。
Moya是个好主意,但我其实觉得稍微思考一下,我们可以用Swift构建一个网络抽象层,代码不多
我们的目标是:
- 灵活性,能够有效地编辑或添加新端点
- 可读性,一目了然地了解我们的 API 是如何工作的
- 代码安全,类型化参数允许我们期望从 Xcode. 获得的所有预编译优点(完成、验证)
- 易于调试,这意味着能够在网络请求前后插入日志
这是我在 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
}
}