I am new to AFNetworking and I know how to pass URL parameters. But how would I pass headers into the same call.
I am also subclassing my AFHTTPSessionManager
See my code below:
- (void)getExpenses:(NSString *)page
success:(void (^) (NSArray *myExpenses))success
failure:(RequestFailureBlock)failure
{
NSString *resourceURL = [NSString stringWithFormat:#"%#/expenses/", APIBaseURLString];
NSDictionary *parameters = #{#"page":page, #"Authorization": APIAuthorization};
[self getExpenses:resourceURL parameters:parameters success:success failure:failure];
}
setAuthorizationHeaderFieldWithToken is deprecated due to servers having different requirements about how the access token is sent (token, bearer, etc)
michaels answer otherwise is correct, use
[self.requestSerializer setValue:#"Some-Value" forHTTPHeaderField:#"Header-Field"];
or
[self.requestSerializer setAuthorizationHeaderFieldWithUsername:#"" password:#""];
for basic auth
You set header values on the requestSerializer property of AFHTTPSessionManager:
[self.requestSerializer setValue:#"Some-Value" forHTTPHeaderField:#"Header-Field"];
EDIT:
It looks like you're trying to set authorization; there is a method for that too:
[self.requestSerializer setAuthorizationHeaderFieldWithUsername:#"" password:#""];
// OR
[self.requestSerializer setAuthorizationHeaderFieldWithToken:#""];
If you need to set the Content-Type header, see this SO answer on how to do that
Related
i know how to add headers in normal to GET or POST request but i couldn't add custom header to upload manager
so if any can help me in that thanks
You can try this to add Header..
NSMutableURLRequest * request;
[request setValue:#"Add your value here" forHTTPHeaderField:#"Set field"];
For Example if you want to add cookie, then
[request setValue:#"frontend=322ybbnbgda6382392du" forHTTPHeaderField:#"Cookie"];
If you are using any of these:
AFURLRequestSerialization#multipartFormRequestWithMethod:URLString:parameters:
or
AFURLRequestSerialization#requestWithMultipartFormRequest:...
All of these methods returns a NSMutableURLRequest, to which you can add the headers using NSMutableURLRequest#setValue:forHTTPHeaderField:.
From there you can use a task, executing for example AFURLSessionManager#uploadTaskWithRequest:fromFile:progress:success:failure: or AFURLSessionManager#dataTaskWithRequest:success:failure: to send the request.
Using AFHTTPRequestOperationManager class you can add header.
AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
[manager.requestSerializer setValue:#"<Your Header String>" forHTTPHeaderField:#"<Key(Parameer Name)>"];
I'm working on an iOS app that was implement in RestKit .10 and am updating it to .20. One of the post requests the app makes has a block of data as a parameter. Previously, the app encoded this use RKParam setData:MIMEType:forParam; I'm looking for the .20 version of this for adding a parameter to a NSMutableDictionary parameter.
Old code:
NSString *logString; // loaded up elsewhere
NSData *textFileContentsData = [logString dataUsingEncoding:NSUTF8StringEncoding];
RKParams *params = [RKParams params];
[params setData: textFileContentsData MIMEType:#"text/plain" forParam:#"log_file"];
New code:
NSMutableDictionary *parameters = [NSMutableDictionary dictionary];
[parameters setObject:???? forKey:#"log_file"]; // not sure how to get string here.
I have tried putting the textFileContentsData NSData object in for ???? but the data arrives in binary, which is not what is required. I need to figure out how to retain the text/plain MIMEType.
TIA
Janene
From your description I wouldn't use RestKit for this as there is no mapping going on, I'd use AFNetworking instead (vehicular is included in RestKit so you already have full access).
Using RestKit, you would use the object manager to create a request to send, something like:
NSMutableURLRequest *request =
[objectManager multipartFormRequestWithObject:nil
method:RKRequestMethodPOST
path:#"..."
parameters:nil
constructingBodyWithBlock:^(id<AFMultipartFormData> formData) {
[formData appendPartWithFormData:...
name:#"..."];
}];
Then you could use RKObjectRequestOperation to process the request. But I'm not convinced this is exactly what you need if you just want to set the mime type (just a header) and the post data, both of which can be done directly on NSMutableURLRequest.
can one AFTHTTPClient handle both json and xml?
I have one single domain in which some services only return json, while others only return xml. How would I make a GET request and instruct AFHTTPClient to use AFJSONRequestOperation for some services and an AFXMLRequestOperation for other GET requests?
So what I would like is:
chairs.com GET customerprofile ---> returns XML (no option for json)
charis.com GET inventory ---> returns JSON (no option for xml)
Is this a job for multiple AFHTTPClients?
Thanks
Your use of AFHTTPClient indicates you're using AFNetworking 1, but I'll answer this question for both versions, for future readers.
AFNetworking 1.x
You just need to register the appropriate AFHTTPOperation subclass. This is typically done in your subclass of initWithBaseURL::
- (instancetype) initWithBaseURL:(NSURL *)url {
self = [super initWithBaseURL:url];
if (self) {
[self registerHTTPOperationClass:[AFJSONRequestOperation class]];
[self registerHTTPOperationClass:[AFXMLRequestOperation class]];
}
return self;
}
When your app makes an outgoing request, you'll need to make sure your accept headers are set appropriately (for example, to text/json or text/xml, depending on what you expect from which endpoint you hit). Otherwise, AFNetworking won't know which operation to use for which request.
There are a few ways to easily solve this Accept header requirement. If one of your endpoints is an exception to a general rule, I might do this by overriding requestWithMethod:path:parameters::
- (NSMutableURLRequest *)requestWithMethod:(NSString *)method
path:(NSString *)path
parameters:(NSDictionary *)parameters {
request = [super requestWithMethod:method path:path parameters:parameters];
if (/* the endpoint specified in path returns XML */) {
[request setValue:#"text/xml" forHTTPHeaderField:#"Accept"];
} else {
[request setValue:#"text/json" forHTTPHeaderField:#"Accept"];
}
}
This is a small violation of tell, don't ask; feel free to refactor as necessary.
If you don't plan on upgrading to AFNetworking 2, then you can stop reading here.
AFNetworking 2.x
Version 2.0 of AFNetworking makes this simpler and more intuitive. In 2.0, the serialization responsibility is broken out into a separate class. Instances of this class are called response serializers. When you upgrade, you'll want an AFCompoundResponseSerializer. The documentation describes it best:
AFCompoundSerializer is a subclass of AFHTTPSerializer that delegates the response serialization to the first AFHTTPSerializer object that returns YES to validateResponse:data:error:, falling back on the default behavior of AFHTTPSerializer. This is useful for supporting multiple potential types and structures of server responses with a single serializer.
For example:
AFJSONResponseSerializer *jsonSerializer = [AFJSONResponseSerializer serializerWithReadingOptions:0];
AFXMLDocumentSerializer *xmlSerializer = [AFXMLDocumentSerializer serializerWithXMLDocumentOptions:0];
AFCompoundResponseSerializer *compoundSerializer = [AFCompoundResponseSerializer compoundSerializerWithResponseSerializers:#[jsonSerializer, xmlSerializer]];
[AFHTTPSessionManager manager].responseSerializer = compoundSerializer;
I followed the suggested solution at AFNetworking 2.0 add headers to GET request to specify custom headers for the request with the following code snippet:
AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
manager.requestSerializer = [AFJSONRequestSerializer serializer];
[manager.requestSerializer setValue:someID forHTTPHeaderField:#"some_id"];
NSDictionary *parameters = #{#"id": user.id, #"birthday": user.birthday};
[manager POST:[NSString stringWithFormat:#"%#/user_create",BaseURLString] parameters:parameters
success:^(AFHTTPRequestOperation *operation, id responseObject)
{
if (responseObject[#"error"])
{
NSLog(#"REST User Create Response Error: %#", responseObject[#"error"]);
}
else
{
[self saveUserDetails:responseObject];
}
}
failure:^(AFHTTPRequestOperation *operation, NSError *error)
{
NSLog(#"REST User Create Error: %#", error);
}];
But what happens when this gets executed is I get an error in the response from the API stating all my parameters are missing. This same block of code used to work before (without setting the custom header and when the API didn't require them originally).
Does anybody know how to properly set both custom headers and POST parameters?
Thanks,
Nino
Your code looks fine to me.
A few things to try:
Try using AFNetworkActivityLogger to see what's actually being sent (set it to AFLoggerLevelDebug.) You can also use a web proxy like Charles or a protocol analyzer like Wireshark.
If you determine the data is not being sent properly, set a breakpoint in [AFURLRequestSerialization -requestBySerializingRequest:withParameters:error:]. This is where your HTTP headers and parameters are added to the URL request. The method is pretty straightforward; you should be able to step through and watch as stuff is added to the request and determine why it gets skipped.
NOTE: AFURLRequestSerialization.m contains multiple subclasses of AFURLRequestSerialization. Set a breakpoint in the super implementation, as well as in the AFJSONRequestSerializer implementation.
Examples that could cause this behavior:
parameters is nil.
you've added POST to HTTPMethodsEncodingParametersInURI but
your API is not prepared to handle parameters appended to a URL on a POST request, or
the queryStringSerialization block is nil AND queryStringSerializationStyle is set to something other than AFHTTPRequestQueryStringDefaultStyle.
NSJSONSerialization can't handle your parameters dictionary
One side note (unrelated to your problem), if you use AFHTTPRequestOperationManager's initWithBaseURL: method, and keep a strong reference to your manager, you won't have to do that [NSString -stringWithFormat:] stuff to construct your URL.
I discovered that I should have set my request serializer to the following instead since my API doesn't require JSON-formatted parameters.
manager.requestSerializer = [AFHTTPRequestSerializer serializer];
Hope this helps others dealing with the same situation as mine.
It seems for batch requests, all the parameters are escaped as parts of relative_url, if omit_response_on_success is set to #(false), app will crash with this message: -[__NSCFNumber length]: unrecognized selector
NSDictionary *parameters = [NSMutableDictionary dictionaryWithObjectsAndKeys: #(false), #"omit_response_on_success", nil];
FBRequest *request1 = [FBRequest requestWithGraphPath:self.graphPath
parameters:parameters
HTTPMethod:nil];
[newConnection addRequest:request1 completionHandler:handler batchEntryName:#"entryName"];
If the graphPath is set to #"me/home?omit_response_on_success=0", these will be no output from this operation. Any ideas?
Yes, this option is currently not supported by the SDK as-is, be sure to file a feature request on https://developers.facebook.com/bugs for this.
That should not be a parameter but a key-value in the JSON body of the request, as noted in the docs. I believe the question is rather how to set that key-value in the iOS SDK since we don't have access to the body of the request. From what I could tell there is no way to do it, but I'm not sure if it's a bug.
It's very annoying that Facebook doesn't allow us to set this flag using the iOS SDK. I spent hours trying to figure out a way and this is a little hack I came up with. It should be relatively safe. Just use the RSFBRequestConnection instead of FBRequestConnection:
#interface RSFBRequestConnection : FBRequestConnection
#end
#implementation RSFBRequestConnection
- (NSMutableURLRequest *)urlRequest
{
NSMutableURLRequest *request = [super urlRequest];
NSData *body = request.HTTPBody;
NSString *bodyStr = [[NSString alloc] initWithData:body encoding:NSUTF8StringEncoding];
NSLog(#"%#", bodyStr);
NSString *fixed = [bodyStr stringByReplacingOccurrencesOfString:#"\"relative_url\"" withString:#"\"omit_response_on_success\":false,\"relative_url\""];
request.HTTPBody = [fixed dataUsingEncoding:NSUTF8StringEncoding];
return request;
}
#end