How can i access different models with same plural in loopback? - node.js

I want to access different models with same plurals. Is there any way in loopback to do so, e.g.:
get-account.json
{
"name": "getAccount",
"plural": "account"
}
to access get-account.js and inside it remoteMethod with http path /
get-smtp-account.json
{
"name": "getSmtpAccount",
"plural": "account"
}
to access get-smtp-account.js and inside it remoteMethod with http path /smtp

I think you are missing the point of Restful resources.
The restful specification is all about using the http verbs, representing CRUD actions like this:
GET: READ -
POST: CREATE -
PUT: UPDATE -
DELETE: DELETE
Each model should represent a resource, that would be the name of a single entry in the persistance, for example, account.
Because we are storing a collection of models, we use a "plural" to refer to this resources, thats why all endpoints should be named in plural, in this example that would be accounts.
So, in any restful resource, if you wanna read data from the persistance, you should use
GET http://0.0.0.0/api/accounts
In loopback, you can create relations between models. This relations, are representations of the relations in the persistance (db). So you can create a model called "smtp".
After the relation is made, you can query the account and "include" the smtp relation, bringing together all users with their data.
Check the documentation for more information https://docs.strongloop.com/display/public/LB/Creating+model+relations
If you have more questions, like, how to create relations between models, i'm really happy to help you in another question.

Related

ACL in Node js based on relationships

I'm trying to implement some kind of permission framework in Node js, using sequelize as an ORM (with Postgres). After hours of research, the closest thing I can find to do this with existing npm modules is using acl with acl sequelize to support my stack.
The problem is that it looks like the acl module assigns a role, where that role would get a set of permissions to all instances of a specific resource. However, I need to do permissioning for instances based on existing relationships of that user.
As an example, consider a permissioning system for a simple forum. It gives these permissions for each role:
// allow guests to view posts
acl.allow("guest", "post", "view");
// allow registered users to view and create posts
acl.allow("registered users", "post", ["view", "create"]);
// allow administrators to perform any action on posts
acl.allow("administrator", "post", "*");
Suppose that I want to also add the ability for registered users to also edit their own posts, and the user has a relationship to all the posts they've created.
Is there any way for this module to do this, or any other module that can support this kind of behavior on the database / ORM level?
If not, and I have to implement a custom one, what would the best approach to creating something like this.
There is relatively new library CASL. I'm the author of this library. And it's possible to implement your usecase quite easily:
const { AbilityBuilder } = require('casl')
const ability = AbilityBuilder.define((can, cannot) => {
can('read', 'all')
can(['update', 'delete'], 'Article', { author_id: loggedInUser.id })
})
The code above basically says:
- anyone can read everything
- anyone can update and delete articles where author_id equals logged in user id
Later you can do:
ability.can('delete', 'Post')
//or
ability.can('update', post)
// where post variable is an instance of your Post model
Also there is an article which explains how to integrate CASL with MongoDB and Express exactly for your usecase.

How to find loopback auto generated rest api names?

I was generated loopback.js framework auto generated rest api, I was trying to write acls for the rest api, that table contains multiple relations with other tables. I want to restrict every rest api call by using their names how do I find rest api names to write acls in loopback.js,
I mean if any rest api like "/users/{id}/requests" how to find this kind of rest api name. I am looking for any source or any suggestions.
From LoopBack documentation:
When two models have a relationship between them (see Creating model relations), LoopBack automatically creates a set of related model methods corresponding to the API routes defined for the relationship.
In the following list, modelName is the name of the related model and modelNamePlural is the plural form of the related model name.
belongsTo:
__get__relatedModelName
hasOne:
__create__relatedModelName
__get__relatedModelName
__update__relatedModelName
__destroy__relatedModelName
hasMany:
__count__relatedModelNamePlural
__create__relatedModelNamePlural
__delete__relatedModelNamePlural
__destroyById__relatedModelNamePlural
__findById__relatedModelNamePlural
__get__relatedModelNamePlural
__updateById__relatedModelNamePlural
hasManyThrough:
__count__relatedModelNamePlural
__create__relatedModelNamePlural
__delete__relatedModelNamePlural
__destroyById__relatedModelNamePlural
__exists__relatedModelNamePlural (through only)
__findById__relatedModelNamePlural
__get__relatedModelNamePlural
__link__relatedModelNamePlural (through only)
__updateById__relatedModelNamePlural
__unlink__relatedModelNamePlural (through only)
hasAndBelongsToMany:
__link__relatedModelNamePlural
__unlink__relatedModelNamePlural

Can I change databases on each request (Sails.js)

I have a few PHP scripts which I am in the process of migrating to Node.js. I am using Sails.js for this and I would like to know how I can change databases for each request based on a request parameter.
Currently I have 3-4 identical PostgreSQL databases. Let's just say that each database corresponds to a different client.
Below is a segment of the current PHP script where the database connection is established:
$database = $_GET['db'];
$conn_details = "host=localhost port=5432 dbname=$database user=****** password=******";
$dbconn = pg_connect($conn_details);
Here you can see that the database name is coming from the request parameter "db".
I would like to have a similar functionality in my sails.js controller. I know that i can declare multiple databases in the connections.js and that I can have models use different databases but what i am after is for the models to stay the same and only the database to change based on each request.
I have found 2 similar questions but they have both stayed unanswered for quite some time now. (Here and here)
I think you are looking for something like sub apps
sails-hook-subapps
but it's experimental module. So i wouldn't recommend using it on production. Other option also not good is multiplying your Models like that:
One main model with all methods, attributes and "stuff"
Many models with connections config
In 'parent' model you will select to which model you want to send send action. For example write method:
getModel: function(dbName){
return models[dbName];
}
in models Object you will store all Models with different connections. Not sure how validators will works in this scenario. You need to test if it will not be required do do something like this in child Models
attributes: parentModel.attributes

What is a good pattern for implementing access control in a GraphQL server?

Background:
I have a set of models, including a User and various other models, some of which contain references to a User. I am exposing these models for querying via a GraphQL API generated by Graffiti, backed by a Mongo database using the graffiti-mongoose adaptor. My current REST API (which I am migrating to GraphQL) uses JSON Web Tokens to authenticate users, and has some custom permission logic on the server side to handle access control.
Problem:
I'd like to restrict access to objects in GraphQL based upon the current logged-in user. Some models should be accessible for reads by unauthenticated calls. Most other models should be only accessible to the User who created them. What's the best way to manage access control to objects via the Graffiti-generated API?
In general, are there good patterns of access control for GraphQL? And in particular, are there any good examples or libraries for doing it with Graffiti?
Notes:
I understand that pre- and post- hooks have been implemented for graffiti-mongoose, and that they can be used to do basic binary checks for authentication. I'd like to see how a more detailed access-control logic could be worked into a GraphQL API. In the future, we'll want to support things like Administrators who have access to model instances created by a certain group of Users (e.g. Users whose Affiliations include that of the Administrator).
Typically GraphQL does not handle access control directly, instead delegating that responsibility to whatever data system it interfaces with. In your case that sounds like Mongoose.
Since access control logic is often arbitrary logic (for example, has this user been banned from some content? did the publisher of that content restrict it with custom privacy settings? etc.), and it sounds like in your case this access control logic is in fact custom, it should live in the "resolve" function which produces a value for a GraphQL field.
For example:
var UserType = new GraphQLObjectType({
name: 'User',
fields: {
name: { type: GraphQLString },
birthday: {
type: GraphQLString,
resolve(user, context) {
var auth = context.myLoggedInAuth;
if (myCanAuthSeeBirthday(auth, user)) {
return user.birthday;
}
}
}
}
});
I create a rule base access control to be used with GraphQL.
https://github.com/joonhocho/graphql-rule
It is simple and unopionated that it can be used with or without GraphQL.
You can use it with a plain javascript objects.
Hope it helps GraphQLers!

Trigger create of one resource from the create of another in Sails.js

If a post has been made to /user, and my data model says that ever user must have a group, how, after successfully creating a user, would I trigger a new group to be created in sails.js? For that matter, how can I get into another controller from a lifecycle callback like afterCreate or via other means?
You cannot call a controller inside a model, that would violate MVC pattern. You can create the group via
Group.create(obj)
or put your creation logic inside a service.
It sounds like you might be confusing models and controllers, which is easy to do if you're new to Sails because of the blueprints functionality it provides. That is to say: you don't need GroupController to create a Group model instances, and GroupController.create is not the correct way to create a new Group programatically. GroupController.create is a method that's called automatically when you POST to /group because Sails has set up a "blueprint" create action at that location.
The correct way to create a Group programmatically is by using the create method of the Group model class, which is globally available in a Sails app. So in your afterCreate, you could have:
afterCreate: function(values, cb) {
Group.create({user: values.id}).exec(cb);
}
Note that the latest version of Sails (v0.10.0-rc5) supports nested creates, so if you've defined User and Group to be associated with each other, you could just POST something like this to /user:
{
name: "Joe Blow",
age: 25,
group: {
name: "Joe's group"
}
}
and the group will be created and associated with the user automatically. If you POST an embedded Group with a primary key, it will search for an existing group with that key and link it to the new User instead of creating a new Group.

Resources