When you do this:
[client getPath:@"/foo/bar" parameters: @{ @"foo" : @[@"bar", @"baz", @"qux"] }]
You get a URL like this:
/foo/bar?foo[]=bar&foo[]=baz&foo[]=qux
But, not every service expects [] at the end of the name. From looking at the source, I don鈥檛 _think_ there鈥檚 any way to make requests with more than one same-named parameter without it. Am I missing something?
No, this is by design. If your web service uses a different convention you have three options:
parameterEncoding to AFJSONParameterEncoding.requestWithMethod:... in a subclass and adjust the query string parameter encoding yourself.I guess you have a bug 'by design'.
Please have a look at the specs http://www.w3.org/MarkUp/html-spec/html-spec_8.html#SEC8.2.1
And the example at the bottom of the page.
Specs clearly define:
The fields are listed in the order they appear in the document with the name
separated from the value by `=' and the pairs separated from each other by `&'.
By changing the field name you corrupt the data, the field name is foo and not foo[]. Specs explicitly forbid doing that.
If library is trying to match some rouge service implementation, it should be defined as an option, rather than by design.
I propose to make a flag that enable adding a certain suffix to the parameter name.
@IvanLatysh Those are specs for HTML. There are no specs that I know of with respect to query string parameter serialization for HTTP.
If library is trying to match some rouge service implementation, it should be defined as an option, rather than by design.
Every Ruby web application framework encodes parameters this way. Many others do to. This will become more extensible in AFNetworking 2.0. See #949
You are mistaken, specs clearly define how multivalued parameters has to be serialized.
Since your library play a role of a user agent, HTML specs would be the ones that concern you. As you perform form data serialization.
P.S. From HTTP protocol point of view both requests are correct:
/foo/bar?foo[]=bar&foo[]=baz&foo[]=qux
/foo/bar?foo=bar&foo=baz&foo=qux
The specs you linked to define how HTML is supposed to encode parameters from a <form>, which is orthogonal to how an API client may encode that information when communicating with a server. As you correctly point out, both requests are valid wrt/HTTP, but that's not the point.
Believe me, I _wish_ there was an RFC that settled this, but as far as I know, there isn't one.
There are no other reference implementation available beside html user agent. So it can and should be taken as a correct implementation.
In any case library should not corrupt the data.
As I said before, an addition of '[]' should be optional, and configuration driven, as it corrupt the data.
foo[] is not the same as foo
P.S. Don't understand the urge to close this issue ...
I'm also running into this issue. Here's an example of a public web service that uses the convention that doesn't include the brackets for arrays: http://www.nextbus.com/xmlFeedDocs/NextBusXMLFeed.pdf
This is also not as easy to subclass my way around as I had hoped, because the encoding is all done in functions like AFQueryStringPairsFromKeyAndValue that aren't even a part of the class definition. I suppose I could write a subclass and copy and paste the code for requestWithMethod and have it call my own function, but that's a lot of work to make AFNetworking support this query parameter format that does actually exist in the real world, regardless of what most web frameworks do.
@stevenp Thats what i had todo :/
use NSSet instead of NSArray
AFHTTPClient.m: AFQueryStringPairsFromKeyAndValue
else if ([value isKindOfClass:[NSSet class]]) {
NSSet *set = value;
for (id obj in set) {
[mutableQueryStringComponents addObjectsFromArray:AFQueryStringPairsFromKeyAndValue(key, obj)];
}
}
There's an active discussion about how to provide more flexibility for these encoding conventions ongoing in https://github.com/AFNetworking/AFNetworking/issues/940
I rolled my own serialization support in RestKit based on MIME type registration because I found the AFN implementation too rigid to support alternate serialization approaches.
I solved this problem overriding requestWithMethod. I know this is not perfect but at least it works. Does anyone have a better solution?
if ([method isEqualToString:@"GET"])
{
NSString *stringUrl = request.URL.absoluteString;
stringUrl = [stringUrl stringByReplacingOccurrencesOfString:@"%5B%5D=" withString:@"="];
request.URL = [NSURL URLWithString:stringUrl];
}
return request;
}
@raphaeloliveira: the workaround proposed by @viking2009 just works: using NSSet as the collection type will repeat the parameter name in the query string without appending []
With AFNetworking 2.0, a better way to handle this would be to set the requestSerializer to POST or PUT the parameters as JSON:
// httpClient is your subclass of AFHTTPRequestOperationManager or AFHTTPSessionManager
httpClient.requestSerializer = AFJSONRequestSerializer;
Note that this only happens for POST and PUT requests (not for GET, HEAD or DELETE) as noted in the migration guide:
For requests with methods not included in
HTTPMethodsEncodingParametersInURI,AFJSONResponseSerializerwill encode parameters as JSON in the HTTP body, setting theContent-Typeheader accordingly
Most helpful comment
use NSSet instead of NSArray
AFHTTPClient.m: AFQueryStringPairsFromKeyAndValue
else if ([value isKindOfClass:[NSSet class]]) {
NSSet *set = value;
for (id obj in set) {
[mutableQueryStringComponents addObjectsFromArray:AFQueryStringPairsFromKeyAndValue(key, obj)];
}
}