Is there any way to use RestKit in an unrestful way?
For example, If I set up an object mapping as such:
[manager.router routeClass:[BBMediaResourceCreate class]
toResourcePath:#"/mediaresources"
forMethod:RKRequestMethodPOST];
RestKit will expect that I post a BBMediaResourceCreate object and receive one back also.
My API however, for reasons I won't go into, is not RESTful compliant in some situations. Rather than receive the newly created resource, I'll get something more like:
{ Model: { Success:true} }
or something similar
Is there a way to map a RestKit post to post a resource of one type but expect a response of another type?
Thanks.
When using v0.10 you can simply set resourcePath:#"/"and respond to
- (void)objectLoaderDidLoadUnexpectedResponse:(RKObjectLoader *)objectLoader
or
- (void)objectLoader:(RKObjectLoader *)objectLoader didLoadObject:(id)object
and handle the response in [objectLoader response] like you want. Keep in mind that posting to that resource then needs an explicit, manually set path.
Related
We want to create a NMARoute without calling [NMACoreRouter calculateRouteWithStops: ...] as it send an unnecessary HTTP call to here.com. Because we already have every information to create a NMARoute object, we just want to initialize it. Unfortunately there is no public initializer. Is there any other approach to initialize a NMARoute object?
Take a look at route serialization:
https://developer.here.com/documentation/ios-premium/topics/route-serialization.html
Basically, the gist of it is that you can create a route based on an NSData object:
https://developer.here.com/documentation/ios-premium/topics_api_nlp_hybrid_plus/interfacenmaroute.html#topic-apiref__routefromserializedroute-colon-error-colon
Note:
The route data depends directly on the map data on your device. The routing data can become obsolete with a map update, and deserialization may not be valid.
I'm trying to use RestKit because I'm expecting to make Core Data managed objects out of requests responses and it seemed like the framework was all about doing that and it seemed to be rather full featured.
But I'm having trouble getting my POST /user/login with parameters api_key=<value> (plus a separate JSON body) to end up a going out in a request like /user/login?api_key=<value>.
In the internals of RKObjectManager, requestWithMethod:path:parameters: does:
// NOTE: If the HTTP client has been subclasses, then the developer may be trying to perform signing on the request
NSDictionary *parametersForClient = [self.HTTPClient isMemberOfClass:[AFHTTPClient class]] ? nil : parameters;
request = [self.HTTPClient requestWithMethod:method path:path parameters:parametersForClient];
Do I have it right that this AFNetworking superclass method encodes parameters into the URL query? And does this mean the only way to ensure parameters are passed to that is to have my RKObjectManager use some subclass of AFHTTPClient?
And, according to the comment, supposedly this is only for sake of maybe a fringe case, something about request signing or something? Why is URL query-encoded request parameters not a common thing to do??
And getting things JSON encoded like I want does not seem to be as easy as I'd hoped either. Maybe it's a mistake for me to even try to use RestKit.
Let's suppose I have a Core Data model using AFIncrementalStore, and I have multiple REST API endpoints for retrieving a list of objects of that model. I can override -requestForFetchRequest:withContext: in AFHTTPClient like so:
- (NSURLRequest *)requestForFetchRequest:(NSFetchRequest *)fetchRequest
withContext:(NSManagedObjectContext *)context {
NSMutableURLRequest *mutableURLRequest = nil;
if ([fetchRequest.entityName isEqualToString:#"Post"]) {
mutableURLRequest = [self requestWithMethod:#"GET" path:#"/posts/foo" parameters:nil];
}
return mutableURLRequest;
}
In this snippet, I retrieve Post objects at /posts/foo, but I also need to retrieve another set from /posts/bar.
How can I do this? The only solution I see is to make two models: one for foo and one for bar, but repeating yourself is lame, and there may be many more API endpoints that get Post objects for me that I'll need to support. Is there some other approach that I'm missing?
You need to inspect fetchRequest more closely than just looking at entityName. You can also look at fetchRequest.propertiesToFetch or possibly other things depending on your data model. You'll still need to send two requests, so just make sure your AFNetworking subclass can tell the difference.
Also: it sounds like your requestForFetchRequest:withContext: method might get really big. You might want to consider a more generic pattern in which you get your NSManagedObject subclass, and ask that to return a fetch request.
My web application makes a REST call. If the call is successful, it will return a 'weather' json object. If the call fails, it will return a json error object.
I want to make a class that parses the resulting JSON and returns a Weather object if the call succeeded and an Error Object if the call failed.
I'm thinking of using the Factory pattern but I'm not sure if that's a good approach because the two objects are very different from one another. What is a good way to design this code?
A common approach I use is to have Weather and Error both be Response objects and have a ResponseFactory create them.
I strongly encourage you to use proper HTTP codes when designing your service as they give a more general view of the state and success of each call.
You need first to check the result of the call, and then make a decision on how to handle it, with the possibility of handling all error codes with an error callback that returns an Error JSON object, and a success callback to return a Weather JSON object. You can use the HTTP codes to create a proper response and further subdivide the logic to return more specific errors, if needed.
The use of a Factory pattern seems overkill, specially given that the objects don't relate to each other.
It really depends on the environment you'll be using your API.
As a rule of thumb, rely on the HTTP code - if you get a 404 or a 500 of course you can't come up with a parsed response.
Format your error responses in a consistent way, e.g.
404 { "message" : "Resource not found" }
400 { "message" : "Wrong parameters given" }
So you know how to parse them.
If you get a 200 OKyou know everything was right, and you can parse your response with no problem at all.
Does the Content-Type header vary depending on the type of response?
As some have noted in their answers, the HTTP status code should be used to determine "Was there an error", but just as important is the interpretation of the content type returned.
Hoping the Content-Type header does vary, I would suggest using a registry of parsers, registered by content-type they handle, and then delegate to them to handle understanding how to convert a particular content type into the object you want. In Ruby, since you didn't specify a particular language:
case response.status:
when 200..299
return parsers[response.content_type].parse(response.body)
when 400..499
raise parsers[response.content_type].parse(response.body)
else
raise "Unhandled response status"
Doing so separates the two concerns:
Determining if there was an error
Parsing of content types into classes/types in your application.
Is there a way to get the response back from a extremely basic RestKit call, before making any GETs or POSTs? I'm just extremely confused because I have a bunch of RESTful calls I want to make, but they all require a user_id as a part of the call. How do I get the response from the initial server interaction, which I'm assuming will contain the user_id.
Do we need to build an GET API call that accepts username and password and returns the user_id, or is there a way to do that part through RestKit? I feel like it should be done through the RestKit client...
UPDATE:
We were missing a needed API call. DOH!
I dont understand exactly what you want to know:
"Is there a way to get the response back from a extremely basic RestKit call?"
- what is this RestKit call exactly? Every restKit call delegate response or error for you mostly used the following RKRequestDelegate methods:
- (void)request:(RKRequest *)request didLoadResponse:(RKResponse *)response {
RKLogInfo(#"Yay! We Got a response");
}
- (void)request:(RKRequest*)request didFailLoadWithError:(NSError *)error {
RKLogInfo(#"Oh no! We encountered an error: %#", [error localizedDescription]);
}
"How do I get the response from the initial server interaction, which I'm assuming will contain the user_id."
What is your initial server interaction exactly and what is the server answer what you receive?
Of course, your server should make this user_id available for you.
Is it maybe a solution for the login process in your case:
Looks like the correct way to configure this is as follows..
RKObjectManager* objectManager = [RKObjectManager objectManagerWithBaseURL:#"http://apihost.com" ];
objectManager.client.username = #"your-user-name";
objectManager.client.password = #"your-password";