What's the best practice to Logout and clean up the Authorization Header, etc. with RESTKit 0.20?
Will this method suffice?
RKObjectManager *objectManager = [self getObjectManager];
[objectManager.HTTPClient clearAuthorizationHeader];
If you use one of the setAuthorizationHeaderField* methods on the http client to add the authorisation then calling clearAuthorizationHeader is the correct approach to take.
If you explicitly set the header or parameter then you need to clear that header or stored attribute.
Related
I would like to modify HTTP headers of the request responses using AFHTTPSessionManager (the final goal is to modify the Cache-Control header in order to force caching).
I didn't find any delegate, block in order to do such things. Did I miss something? Maybe by subclassing AFHTTPSessionManager? Any idea how to do this the right way?
Regards,
Quentin
I hope this is what you need
[sessionManager.requestSerializer setValue: maxAge forKey:#"cache-control"];
And you can use this for referring how to set-up the header.
You can similarly set-up sessionManager.responseSerializer
It seems to me that the proper place to do this is in AFURLSessionManager, in setting the taskWillPerformHTTPRedirection block, but I am unsure of the best way to handle it.
Currently, in my AFHTTPSessionManager subclass, I am setting the redirect block globally for all requests, and I know I can prevent redirects by returning nil here:
- (void)setupRedirectBlock {
[self setTaskWillPerformHTTPRedirectionBlock:^NSURLRequest *(NSURLSession *session, NSURLSessionTask *task, NSURLResponse *response, NSURLRequest *request) {
return nil;
}];
}
...but I need to only do this on specific tasks, and there doesn't appear to be a way to get this information from the task itself.
I guess I am looking for some sort of user info dictionary or something I can use to set a flag telling this method to either return the request or return nil. Currently, it looks like I would have to do a string comparison on the response/request URL in the client where it is far away from where the task and path is actually created.
So this begs the question, am I fighting convention, or is there really no better way to intercept an AFNetworking 2.0 redirect on a task-by-task basis?
setTaskWillPerformHTTPRedirectionBlock is the best way to intercept redirects. The session manager is responsible for determining when or when not to prevent redirects based on the request associated with the task. In most cases, the path of the request should be a sufficient determination, but the user could additionally tag information in a custom request header field.
I have the same question, but unfortunately I don't yet have a good enough answer. One workaround could be using taskDescription https://developer.apple.com/library/ios/documentation/Foundation/Reference/NSURLSessionTask_class/Reference/Reference.html#//apple_ref/occ/instp/NSURLSessionTask/taskDescription
Just put there some constant like DO_NOT_FOLLOW_REDIRECT and check for it in your setTaskWillPerformHTTPRedirectionBlock block.
When I use AFHTTPRequestOperationManager, I can use the HTTPRequestOperationWithRequest method with NSURLRequest object. With this object, I can configure the request object with http body in which I can put a xml file.
Now I try to use the newer AFHTTPSessionManager, I only can use the GET, POST, etc. How I can put a xml file in the http request's body? Thanks.
In AFNetworking 2, a new object called the "request serializer" is how you are supposed to create your request body. There is no built-in serializer for posting XML. You'll need to subclass AFHTTPRequestSerializer, and set it as your manager's request serializer, like so:
[AFHTTPSessionManager manager].requestSerializer = [YourXMLRequestSerializer serializer];
When you subclass AFHTTPRequestSerializer, you'll need to override requestWithMethod:URLString:parameters:error: to return an NSMutableURLRequest with your desired content.
I would like to use RestKit 0.20 on my app but I am a bit confused on how the pieces fit together. Each one of my view controllers needs to get data from the server each with their own route on the server returning a different object. I would like to keep all of the server requests away from the view controllers so I can manage them centrally (but open to another setup if it makes sense). Right now I have the following setup but I am pretty sure there is a better way to go about it using RKObjectManager and RKRouter :
1) Each view controller triggers a method in a Gateway object that is dedicated to it.
2) The method will create a request and a response map. Then a request and response description and finally a request operation that uses a manually created NSURL.
3) In the success block I pass the response to the view controller with an NSnotification.
Is there a better setup? Can I just use one RKObjectManager for all the request? How does that work? Do I put it in a separate method in my gateway? Is there a better way to get back to my view controller then NSNotification?
Sorry if some of these are very basic.
I would suggest the following structure (using Instagram as an example):
1) first of all split all your requests based on the "Resource" you use e.g. Users/Comments/Likes, etc
2) For each "Resource" create a separate class, subclass of RKObjectManager, for example UsersManager, CommentsManager, LikesManager (all inherited from RKObjectManager)
3) Define extra methods on every manager, that you will use from View Controller.
For example, for loading "likes" resource for user, you'd define this method in LikesManager (or UserManager) -- this is very opinionated decision, and it's really up to you.
- (void)loadLikesForUser:(User *)user
success:(void (^)(NSArray *likes))successCallback
failure:(void (^)(NSError *error))failureCallback;
4) Implement this method and call appropriate methods using self, because you've created a subclass of RKObjectManager class and have access to all basic methods.
[self getObjectsAtPath:#"/resources/" parameters:nil success:^(RKObjectRequestOperation *operation, RKMappingResult *mappingResult) {
// pass mappingResult.array to the successCallback
} failure:^(RKObjectRequestOperation *operation, NSError *error) {
// pass error object to the failureCallback
}];
5) In your view controller, you'd call this like
[[LikesManager sharedManager] loadLikesForUser:user success:^(NSArray *likes) {
self.likes = likes;
// work with likes
} failure:^(NSError *error) {
// handle error
}];
Notice that you don't do any stuff with NSNotification, as it'll be a bad design decision in this kind of situations.
Generally speaking you can put all of your requests in a subclass of RKObjectManager, if you have very few of them, but if you have more than 5-6 requests, you'll find it tedious and hard to manage to keep all of them in one file. So that's why I suggest to split them based on a Resource.
UPDATE
Based on questions asked in comments, providing answers here
a) Where to set Base URL?
Base URL is a property on instance of RKObjectManager, so you definitely want to set it before making any requests to API. To me ideal place would be at the initialization of RKObjectManager instance.
b) Where to define Object Mapping?
Again it's up to you. Answer to this question is very opinionated. I'd consider 2 options:
create a separate class to hold all your objects related to mappings, like MappingProvider. Then whenever you create RKResponseDescriptor or RKRequestDescriptor, you'd just access properties of MappingProvider to get your mappings.
Define mappings in manager's class, because you'll assign them to the RKResponseDescriptor instances that will be used in this manager.
UPDATE: Check out this blog post on RestKit setup: http://restkit-tutorials.com/code-organization-in-restkit-based-app/
I have to communicate with a REST API with a custom authorization scheme. It uses a authorization header witch I need to set based on the content of the request, so the server can check that I known the scheme.
I would like to use RestKit and its powerful Core Data utilization but I found it difficult to find a neat way to set this header for every different request. There isn't a thing like a delegate on RKObjectManager that is called before every request.
Maybe I missed something, could someone tell me if there is an easy way to do this? Thanks in advance.
You can do something like
[RKObjectManager sharedManager] postObject:yourObjectToPost usingBlock:^(RKObjectLoader *loader) {
NSDictionary* httpHeaders =#{#"key1":#"value1",
#"key2":#"value2",
#"key3":#"value3"};
loader.additionalHTTPHeaders = httpHeaders;
loader.delegate = self;
}];