In RestKit, what is the best way to RKRoute the GET of a list of objects as well as a single object? - restkit

Most RESTful APIs would route access to a resource, say Rabbit objects, like this:
GET /rabbits <--- GET all rabbits. HTTP GET
GET /rabbits/:rabbit_id <--- GET one rabbit. Also HTTP GET
POST /rabbits
PUT /rabbit/:rabbit_id
However, RestKit doesn't allow me to have two routes with the same HTTP verb, so this is impossible to add two GET routes to the RKObjectManager's RouteSet:
[manager.router.routeSet addRoute:[RKRoute routeWithClass:[Rabbit class]
pathPattern:#"rabbits"
method:RKRequestMethodGET]];
[manager.router.routeSet addRoute:[RKRoute routeWithClass:[Rabbit class]
pathPattern:#"rabbits/:rabbitID"
method:RKRequestMethodGET]];
//BOOM! Assertion failure
This causes an assertion failure: "Cannot add a route with the same class and method as an existing route."
Why can't I add a route with the same class and method? The path is different. How am I supposed to get both a list of Rabbits as well as a single Rabbit by ID? I know several workarounds, but I feel like this isn't something I should have to work around.

If you use named routes you can do it. You can't use non-named routes because it generates an ambiguity into which one RestKit should use.

The object class routes are designed to work with instances. The GET route in particular is used when you perform getObject:someObject path:nil parameters:nil success:nil failure:nil.
Collection loads are typically done via named routes or paths.

In case it helps anyone with the code, heres how to set up the route with name.
// When you are setting up your mapping, set up Route with Name.
RKResponseDescriptor *responseDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:userMapping
method:RKRequestMethodGET
pathPattern:LOGIN_URL
keyPath:nil
statusCodes:RKStatusCodeIndexSetForClass(RKStatusCodeClassSuccessful)];
[[RKObjectManager sharedManager].router.routeSet addRoute:[RKRoute routeWithName:LOGIN_ROUTE pathPattern:LOGIN_URL method:RKRequestMethodGET]];
[[RKObjectManager sharedManager] addResponseDescriptor:responseDescriptor];
// And when you are ready to make the http call, do the following
[[RKObjectManager sharedManager] getObjectsAtPathForRouteNamed:LOGIN_ROUTE
object:userProfile
parameters:params
success:success
failure:failure];

Related

Why I put the DELETE router after GET, the DELETE endpoint did not get triggered

I was creating restful API with Golang and I put the delete router after the getOne router by index, and the delete router never got triggered? I don't know why? When I reverse them, it works!
Can someone know the reason??
This is for Building Restful API with Golang.
Not works:
myRouter.HandleFunc("/article", createNewArticle).Methods("POST")
myRouter.HandleFunc("/article/{id}", getOneArticle)
myRouter.HandleFunc("/article/{id}", deleteArticle).Methods("DELETE")
Works!
myRouter.HandleFunc("/article", createNewArticle).Methods("POST")
myRouter.HandleFunc("/article/{id}", deleteArticle).Methods("DELETE")
myRouter.HandleFunc("/article/{id}", getOneArticle)
When I test the api using postman with DELETE methods, it always trigger the getOneArticle and respond with the delete item, but did not actually delete in the database!
You're using gorilla/mux. When an HTTP request comes in, this router tries to match routes in the order in which you add them.
When you add the route without specifying an HTTP method, it applies to all HTTP methods.
So, if your more specific route matching the DELETE method comes first, then it will match DELETE method calls, and the next route will match all methods. While it would match DELETE also, an actual DELETE call would never reach it because of the route preceding it.
But if you reverse them, the route which doesn't specify an HTTP method will match all methods, including DELETE.
Gorilla/mux matches the routes in an order in which you have defined them. Without specifying the Http Method it will match it no matter what you have selected from the postman i.e. GET, DELETE
for instance, you have a route /todo/1 and the method is not specified, It will run in case of GET, DELETE, POST and PUT.
Note
Same route with method DELETE defined under the first one will never get triggered.

HTTP Requests in Laravel

In Laravel we use routes to deal with HTTP requests from the browser.
We can route a request to a controller, do some logic and then return a response.
Now, we can send in variables encapsulated with braces {} and the response can be anything, so it seems to me that routing through a controller means that the the properties of the different request methods (POST, GET, PUT etc.) are lost.
For example I could send a POST request with URI example/{id} then put in my routes.php file
Route::post('example/{id}','SomeController#SomeAction');
Then I could do something in my controller with the variable $id and send a response.
On the other hand I could send a GET request with URI example/{id} and alter my route to
Route::get('example/{id}','SomeController#SomeAction');
The controller would give the same response.
So, am I right in thinking it does not really matter what request method is used?
Two parts of your question I can identify on a second read-through:
Request methods are not lost. You have access to them with $request->getMethod(). So a GET request will return GET. You also have the method isMethod('GET') available to you, which you could use to get a truthy value which would enable you to return a different kind of response depending on the request type.
With regards to the way you set up your URL, what HTTP verb you use does matter if you're creating a REST-ful web service.
I won't explain away what a REST-ful web service is (you can look it up), here is a couple of points from your example:
If you're getting some data, you ought to be doing a GET request. It is the verb to represent a read from a resource. If you had to send a lot of data - and your intention is to add data, you ought to POST it instead.
The URI should be meaningful in a way that best describes the resource you are manipulating.
Together with the HTTP verb, you can infer the implied action. So if you are POSTing to example/1, I might infer that (and this is a digression, actually) that you are attempting to update record 1 from an example resource. In reality, you would perhaps use the PUT verb (which handles update).
Behind the scenes, Laravel uses a POST request due to browser limitations but treats it as a PUT request server-side.
Of course request type does matter. When you want to hide some request data against user and dont show it in url for example:
?username="Admin"&nick="admin1" then u will use POST otherwise you can use GET. When you want get some data u will use GET but when you want to send some data then you should use POST instead.

Laravel RESTful routing

Consider the following 3 lines of code in a routes file:
Route::pattern('token', '[0-9a-z]+');
Route::get('user/reset/{token}', 'UserController#getReset');
Route::controller('user', 'UserController');
Are the pattern and get routes serving any purpose in this example? As I understand it, the RESTful controller route at the bottom will match any user/reset/{target} URL to the UserController getReset action, regardless of any token pattern supplied.
Is it possible to use a regex constraint on a route like this, where there is also a "catch-all" controller route?
The extra routes aren't needed in this example.
Right now, all the /user/reset requests are going to getReset. You could either send the constrained route to a different method, or neater, perform the validation in the controller to match the token and throw an exception if it doesn't match your constraints (or pass them off to your catch all idea).
Hope that helps.

How to correctly use stopAccessingSecurityScopedResource on NSURL

A sandboxed App must use Security Scoped Bookmarks in order to save its file access privileges over restarts. The NSURL docs say:
You must balance every call to the
startAccessingSecurityScopedResource
method with a corresponding call to the stopAccessingSecurityScopedResource
method
But I can't see from the docs if I must call the stopAccessing method on the exact same NSURL object that I obtained by resolving a bookmark. (Are these 'magic' NSURL-objects with special properties?)
I would like to call stopAccessing on new NSURL objects, generated from the file path. Of course these point to the same resource. But does it have the same effect?
How can I see if access to a NSURL resource has been stopped?
I'm pretty sure there is metadata in the NSURL object with some kind of token granting access to that resource.
I don't think what you're proposing is the suggested way of doing it, but give it a shot and see if it works.
"How can I see if access to a NSURL resource has been stopped?"
stopAccessingSecurityScopedResource is a void method, not boolean, and there seems to be no way to test the resource to see if it has been "stopped".
(void)stopAccessingSecurityScopedResource
I conclude that you must keep track of it yourself.

Change CodeIgniter route for static pages and auth login [duplicate]

I have a problem with Codeigniter routes. I would like to all registered users on my site gets its own "directory", for example: www.example.com/username1, www.example.com/username2. This "directory" should map to the controller "polica", method "ogled", parameter "username1".
If I do like this, then each controller is mapped to this route: "polica/ogled/parameter". It's not OK:
$route["(:any)"] = "polica/ogled/$1";
This works, but I have always manually entered info in routes.php:
$route["username1"] = "polica/ogled/username1";
How do I do so that this will be automated?
UPDATE:
For example, I have controller with name ads. For example, if you go to www.example.com/ads/
there will be listed ads. If you are go to www.example.com/username1 there are listed ads by user username1. There is also controller user, profile, latest,...
My Current routes.php:
$route['oglasi'] = 'oglasi';
$route['(:any)'] = "polica/ogled/$1"
$route['default_controller'] = 'domov';
$route['404_override'] = '';
I solved problem with this code:
$route['oglasi/(:any)'] = 'oglasi/$1';
$route['(:any)'] = "polica/ogled/$1"
$route['default_controller'] = 'domov';
$route['404_override'] = '';
Regards, Mario
The problem with your route is that by using :any you match, actually...ANY route, so you're pretty much stuck there.
I think you might have two solutions:
1)You can selectively re-route all your sites controller individually, like:
$route['aboutus'] = "aboutus";
$route['where-we-are'] = "whereweare";
//And do this for all your site's controllers
//Finally:
$route['(:any)'] = "polica/ogled/$1";
All these routes must come BEFORE the ANY, since they are read in the order they are presented, and if you place the :any at the beginning it will happily skip all the rest.
EDIT after comment:
What I mean is, if you're going to match against ANY segment, this means that you cannot use any controller at all (which is, by default, the first URI segment), since the router will always re-route you using your defined law.
In order to allow CI to execute other controllers (whatever they are, I just used some common web pages, but can be literally everything), you need to allow them by excluding them from the re-routing. And you can achieve this by placing them before your ANY rule, so that everytime CI passed through your routing rules it parses first the one you "escaped", and ONLY if they don't match anything it found on the URL, it passes on to the :ANY rule.
I know that this is a code verbosity nonetheless, but they'll surely be less than 6K as you said.
Since I don't know the actual structure of your URLs and of your web application, it's the only solution that comes to my mind. If you provide further information, such as how are shaped the regular urls of your app, then I can update my answer
/end edit
This is not much a pratical solution, because it will require a lot of code, but if you want a design like that it's the only way that comes to my mind.
Also, consider you can use regexes as the $route index, but I don't think it can work here, as your usernames are unlikely matchable in this fashion, but I just wanted to point out the possibility.
OR
2) You can change your design pattern slightly, and assign another route to usernames, something along the line of
$route['user/(:any)'] = "polica/ogled/$1";
This will generate quite pretty (and semantic) URLs nonetheless, and will avoid all the hassle of escaping the other routes.
view this:
http://www.web-and-development.com/codeigniter-minimize-url-and-remove-index-php/
which includes remove index.php/remove 1st url segment/remove 2st url sigment/routing automatically.it will very helpful for you.
I was struggling with this same problem very recently. I created something that worked for me this way:
Define a "redirect" controller with a remap method. This will allow you to gather the requests sent to the contoller with any proceeding variable string into one function. So if a request is made to http://yoursite/jeff/ or http://yoursite/jamie it won't hit those methods but instead hit http://yoursite/ remap function. (even if those methods/names don't exist and even if you have an index function, it supersedes it). In the _Remap method you could define a conditional switch which then works with the rest of your code re-directing the user any way you want.
You should then define this re-direct controller as the default one and set up your routes like so:
$route['(.*)'] = "redirect/index/$1";
$route['default_controller'] = "redirect";
This is at first a bit of a problem because this will basically force everything to be re-directed to this controller no matter what and ultimately through this _remap switch.
But what you could do is define the rules/routes that you don't want to abide to this condition above those route statements.
i.e
$route['myroute'] = "myroute";
$route['(.*)'] = "redirect/index/$1";
$route['default_controller'] = "redirect";
I found that this produces a nice system where I can have as many variable users as are defined where I'm able to redirect them easily based on what they stand for through one controller.
Another way would be declaring an array with your intenal controllers and redirect everything else to the user controller like this in your routes.php file from codeigniter:
$controllers=array('admin', 'user', 'blog', 'api');
if(array_search($this->uri->segment(1), $controllers)){
$route['.*'] = "polica/ogled/$1";
}

Resources