Suppose I have 3 models A, B, C. Is there any way to enable rest API for model C only?
blueprints.js can only turn on/off the rest API function for all models.
I think if it can't be configured, a controller is needed.
You need a controller to override the configurations of your blueprints, since you only want one model to have rest API, then you can set it to false(globally) in your blueprint settings, and for that particular model(C), you create a controller and add a custom _config property that will override what was set in the blueprints settings.
Like this
var ModelController = {
_config: {
actions: true,
shortcuts: true,
rest: true
}
}
module.exports = ModelController
According to the docs the opposite is true (dissabling), and its what i've tried in the past, but i believe it will work like this. If not, you'll have to enable the restApi for all of them and disable it for all but your model C controller.
This is the link to the docs related to that http://sailsjs.org/documentation/reference/blueprint-api
I'm not aware of any other option right now, but let me know if it works.
Related
I'm new to sails, using 1.0.
I created an app with the --minimal command line switch and now I wish to add in some functionality.
I've already successfully added the ORM functionality (by adding sails-hook-orm, config/datasources and config/models.
Now I wish to enable the automatic blueprint routes. I've already added config/blueprint like so:
module.exports.blueprints = {
prefix: '/api/v1',
actions: true,
rest: true,
// shortcuts: true,
};
Now, if I manually add in the routes and actually write the standalone actions, for example, like below:
'GET /api/v1/users/:id': { action: 'users/find-one' },
It works. But I was expecting that blueprint would abstract those away from me when I set rest: true on the config...
What else should I check?
By the documentation is just put rest as true (is true by default), and this should work, seem like you have missing something else. Check if you have your controller created and your model with the same name.
controllers
UserController.js
models
User.js
If you don't have the controller created then the blueprint is not going to work
I have set policies at the controller level for few controllers and the specific actions in the controllers. But if i have a model with the name test and when I call the API localhost:<port>/test it returns the response of the whole data which is there under test. Basically it does a test.find()
How do I restrict this ? Something like:
{
"test":"isAuthenticated"
}
I'm using passportjs along with sails.
You can create a policies.js inside config folder and specify the policies for the controller there.
{
// Apply 'isLoggedIn' to all actions by default
'*': 'isLoggedIn',
ProfileController: {
'foo': 'isAdmin'
}
}
isAdmin.js is a js file inside policies directory. You can get more information here
Found a way to add it in the API level.
in my routes:
'/modelName': { policy: 'isAuthenticated' }
I got a basic question.
I'm trying out Sails (http://sailsjs.org/) and it has terminal commands to generate entity such as User entity:
sails generate api user
My question is, the UserController.js file shows:
/**
* UserController
*
* #description :: Server-side logic for managing users
* #help :: See http://sailsjs.org/#!/documentation/concepts/Controllers
*/
module.exports = {
};
How come when I access:
http://localhost:1337/user/create
It knows how to create a new User entity ? The controller clearly does not have a create action like this:
module.exports = {
create: function(req, res) {
// code to create new user
}
};
So surely nothing should happen.
I did a bit of Symphony 2.0 PHP web framework and we needed to create those actions manually.
I'm confuzzled and impressed at the same time, any ideas ?
Welcome to the Sails.js world!
You have just discovered the Blueprint API.
When you lift your app, Sails will add generic actions to your controllers that have a model of the same name (to this day find, findOne, create, update, destroy, populate, add and remove actions exist implicitly). That's called Blueprints actions.
In addition, Blueprints routes can also be binded to your controllers' actions. Here is the list of those routes:
Blueprints RESTful routes: automatically generated routes to expose a conventionnal REST API on top of find, create, update, and destroy actions
GET /post -> PostController.find
GET /post/:id -> PostController.findOne
POST /post -> PostController.create
PUT /post/:id -> PostController.update
DELETE /post/:id -> PostController.destroy
Blueprints shortcuts routes: simple helpers to provide access to a controller's CRUD methods from your browser's URL bar
GET /user/create?name=joe -> Post.create
GET /user/update/1?name=mike -> Post.update
GET /user/destroy/1 -> Post.destroy
Blueprints actions routes: automatically create routes for your custom controller actions
GET /group/count -> Post.count
Each of them can be deactivated in the config/blueprints.js file.
You can find more details on the docs.
Check this SO question if you want to redefine the blueprints actions.
What purpose does req.options serve in SailsJs?
From the source, it seems I can somehow use policies to alter existing params on Sails Blueprints, etc. How does this work? I can't find any documentation at all.
req.options was introduced in Sails v0.10 as a way to add options to custom routes. For example, you could always do:
'GET /userList': {
controller: 'UserController',
action: 'find'
}
to point at the default "find" action for a User model, but there was no way to control the query--it would always just return all records. Now you can do:
'GET /userList': {
controller: 'UserController',
action: 'find',
sort: 'name desc',
where: {name: {startsWith: 'j'}}
}
and all of the options (including controller and action) will be added to req.options, which the default blueprint actions use to modify the query. Note the difference to Sails v0.9.x, which used req.target to keep track of the controller and action.
As you pointed out, req.options can also be modified within policies, as opposed to req.params which are reset before every policy and controller action. This can be used to, for example, further restrict the criteria for a query based on a user's role.
Obviously the docs for v0.10.x aren't completely finished (and will always be subject to improvement), but this could definitely find a place in the Route Target Syntax section...
I'm upgrading a custom solution where I can dynamically register and unregister Web Api controllers to use the new attribute routing mechanism. However, it seems to recent update to RTM break my solution.
My solution exposes a couple of Web Api controllers for administration purposes. These are registered using the new HttpConfigurationExtensions.MapHttpAttributeRoutes method call.
The solution also allows Web Api controllers to be hosted in third-party assemblies and registered dynamically. At this stage, calling HttpConfigurationExtensions.MapHttAttributeRoutes a second time once the third-party controller is loaded would raise an exception. Therefore, my solution uses reflection to inspect the RoutePrefix and Route attributes and register corresponding routes on the HttpConfiguration object.
Unfortunately, calling the Web Api results in the following error:
"No HTTP resource was found that matches the request URI".
Here is a simple controller that I want to use:
[RoutePrefix("api/ze")]
public sealed class ZeController : ApiController
{
[HttpGet]
[Route("one")]
public string GetOne()
{
return "One";
}
[HttpGet]
[Route("two")]
public string GetTwo()
{
return "Two";
}
[HttpPost]
[Route("one")]
public string SetOne(string value)
{
return String.Empty;
}
}
Here is the first solution I tried:
configuration.Routes.MapHttpRoute("ZeApi", "api/ze/{action}");
Here is the second solution I tried:
var type = typeof(ZeController);
var routeMembers = type.GetMethods().Where(m => m.IsPublic);
foreach (MethodInfo method in routeMembers)
{
var routeAttribute = method.GetCustomAttributes(false).OfType<RouteAttribute>().FirstOrDefault();
if (routeAttribute != null)
{
string controllerName = type.Name.Substring(0, type.Name.LastIndexOf("Controller"));
string routeTemplate = string.Join("/", "api/Ze", routeAttribute.Template);
configuration.Routes.MapHttpRoute(method.Name, routeTemplate);
}
}
I also have tried a third solution, whereby I create custom classes that implement IHttpRoute and trying to register them with the configuration to no avail.
Is it possible to use legacy-style route mapping based upon the information contained in the new routing attributes ?
Update
I have installed my controller in a Web Application in order to troubleshoot the routing selection process with the Web Api Route Debugger. Here is the result of the screenshot:
As you can see, the correct action seems to be selected, but I still get a 404 error.
Update2
After further analysis, and per Kiran Challa's comment below, it seems that the design of Web Api prevents mixing attribute routing and conventional routing, and that what I want to do is not possible using this approach.
I have created a custom attribute [RouteEx] that serves the same purpose of the Web Api [Route] attribute, and now my code works perfectly.
I guess, since this is not possible using the conventional attribute routing, none of the answers on this question could legitimately be consisered valid. So I'm not nominating an answer just yet.
You shouldn't be required to use reflection and inspect the attribute-routing based attributes yourself. Attribute routing uses existing Web API features to get list of controllers to scan through.
Question: Before the switch to attribute routing, how were you loading these assemblies having the
controllers?
If you were doing this by IAssembliesResolver service, then this solution should work even with attribute routing and you should not be needing to do anything extra.
Regarding your Update: are you calling MapHttpAttributeRoutes?