I saw that all controllers methods are free for GET and POST. How to ensure to permits only POST for some methods?
If you are using action blueprints to automatically route URLs to custom controller action, then those actions will respond to GET, PUT, POST, DELETE and PATCH methods by default. If you'd rather control which methods are allowed, you have a few choices:
Disable certain methods using custom routes in your config/routes.js file. For example, if you have a foo action in UserController.js that you don't want to allow GET requests for, you can add the following custom route:
"GET /user/foo": {response: 'forbidden'}
to automatically route it to the "forbidden" response (same as doing res.forbidden() in a controller)
Test req.method within the action itself, and return early for methods you don't want to process:
if (req.method.toUpperCase() == 'GET') {return res.forbidden();}
Disable action routes by setting actions to false in your config/blueprints.js file. You'll then have to set up all your routes manually in your config/routes.js file.
Related
I am developing an installable sails-hook that injects some checking on the request before allowing it to pass through the controller action. I want the checking to be done via installable hook, not as a policy, as I will be using the hook in other projects as well.
So, I am doing something like this inside my hook
sails.on('router:before', function() {
//attach middlewares here
sails.router.bind('/route', function(req, res, next) {
//do checking here. if everything is fine, call next()
req.options.controller // ?
}
});
The problem with the above apporach is that the req.options object does not contain the controller and action properties that my middleware depends upon (not now, may be in future).
So, what is the bestway to achieve this? One possible solution is to explicitly attach a policy that executes the middleware. I am looking for better options. Thanks
How can I use the url() controller helper inside the console?
I have to generate some urls using an action of the console, but if I call $this->controller->url()->fromRoute(...);, I can only ask for routes defined in the console router.
In other words, I need the ability to call all the routes of the application's main router.
Thanks
I'm not sure, that it is a good decision, but you can change router manually:
// ConsoleController.php
// Change router to HTTP
$this->getEvent()->setRouter($this->getServiceLocator()->get('HttpRouter'));
// Get any HTTP route
var_dump($this->url()->fromRoute('your_http_route'));
// Change it back, if you want
$this->getEvent()->setRouter($this->getServiceLocator()->get('Router'));
Recently I need to create REST API for existing grails application.
I am thinking that is it really possible to have both of the controllers (Normal and Restful) for same domain class in one single grails application?
Which controller will handle the request if make a HTTP GET request?
Please discuss your thoughts or if it is possible at all please guide me how.
We can define a new Controller to handle to REST API calls. e.g. In my app I have User as Domain Class and have UserController which return the data to GSP pages. I wanted to add REST API support (unfortunately) in the same app and I don't wanted to deal with mess it is already there in UserController. So I added new Controller UserRestController which will specifically handle the REST API calls and following mapping in UrlMappings.groovy which now works fine. Thanks to #codehx for helping me on this.
"/api/users"(controller: "userRest", parseRequest: true) {
action = [GET: "list", POST: "save" }
"/api/users/$id"(controller: "usersRest", parseRequest: true) {
action = [GET: "show", PUT: "update", DELETE: "delete"] }
Which controller will handle the request if make a HTTP GET request?
As far as it is not possible to have two controllers with same name in grails app this will not be confusing.
Just use two different names for Normal controller and for your RESTFUL controller, so obviously the URL for accessing the two urls will be different.
Short question, tried finding an IRC for sails for such a quick one but got lost so here goes. I have a controller with a route of '/userposts'. I know sails offers some default REST-like functionality without backend code needed but what if I want to overwrite the default POST action what would I do?
I'm forced to write a POST route such as post /userposts/create or I can overwrite the default action and post straight to /userposts which will identify my overwriting and execute it.
I hope I'm making sense. I basically want to create a custom POST route and be able to
socket.post('/userposts', {title: "Foo", content: "Bar"}, function(response){});
I tried with create but it doesn't get executed on a post to /userposts
Sails.js provides blueprints out of the box.
These blueprints provide you with the following CRUD routes that are enabled by default
/:controller/find/:id?
/:controller/create
/:controller/update/:id
/:controller/destroy/:id
To modify the default functionality for your controllers, look at the settings in config/controllers.js
Your routes are defined within config/routes.js, in your case you have a model UserPosts and a corresponding controller named UserPostsController.
In your UserPosts controller, create a function createPost and specify the route(s) to this method
'POST /userposts/create': 'UserPostsController.createPost'
which is shorthand for
'POST /userposts/create': {
controller: 'userposts',
action: 'createPost'
}
you can also override the /:controller route
'POST /userposts': 'UserPostsController.createPost'
These routes will map any POST requests made to the createPost function.
For more information, be sure to check out the Sails.js documentation
I've got a pretty standard ACL system in my application. There's a Login controller and a bunch of other controllers redirecting back to Login if user is not authorized. I use a Controller Plugin for checking the ID and redirecting and I obviously don't want Login controller and Error controller to perform such a redirect.
Now I've read several times that using Controller Plugins is a better practice than subclassing the Action Controller. Yet what I see is it's much easier to extend all my controllers from this abstract base controller class which performs the necessary checking in its init method, except for the Login controller which extends Zend_Controller_Action directly.
So the question is, is there a way to attach the plugin to the controllers selectively? Of course I can always make an array out of certain controllers, send it to a plugin through a setter method and do something like:
$controller = $request->getParam('controller');
if (count($this->exceptions))
if (in_array($controller, $this->exceptions)) return;
//...check ID, perform redirect, etc...
Yet something tells me it's not the best way doing it.
And advices?
EDIT 1: #Billy ONeal
Thank you for your reply, but I don't quite catch. I can do
public function init()
{
$this->getRequest()->setParam('dropProtection', true);
}
(or run some method that sets some private variable of the plugin) in my login controller, and then say if 'dropProtection' is not true then check the user ID. But the actual dispatch process looks like this:
Plugin::dispatchLoopStartup
Plugin::preDispatch
Controller::init
Plugin::postDispatch
Plugin::preDispatch
Plugin::postDispatch
Plugin::dispatchLoopShutdown
So I cannot check this 'dropProtection' param earlier than in Plugin::postDispatch and that's a bit late. (by the way, why the preDispatch and postDispatch are being called twice?)
If you want to do it earlier, I think you can use the first method (passing an array of exceptions to the plugin) and test the module name or the controller name in routeShutdown.
Personnaly I use an action helper to check the auth in all my actions. It's more flexible and give me more control. It's only one line for each private action.
And DON'T SUBCLASS your action controller. I did it on one of my project and now my base class is a piece of shit. Use action helper instead.
is there a way to attach the plugin to the controllers selectively?
Of course. Just don't register the plugin if the request doesn't contain the parameters you're looking for. Alternately, assume all pages are protected, and have those pages which should not be protected call some method on your plugin during the init stage.
If you want to protect just a single controller, you could reverse that -- have the plugin only take action if there's some method called during the init stage.
Finally, you could make the entire logged-in section of the page it's own module, which would allow you to have the plugin check for that module before checking credentials and redirecting.