Member model based on User model
{
"name": "Member",
"base": "User",
"idInjection": true,
"options": {
"validateUpsert": true
},
"properties": {
"nickname": {
"type": "string"
}
},
"validations": [],
"relations": {
"messages": {
"type": "hasMany",
"model": "Message",
"foreignKey": ""
},
"followers": {
"type": "hasMany",
"model": "Member",
"foreignKey": "followeeId",
"through": "Follow"
},
"followings": {
"type": "hasMany",
"model": "Member",
"foreignKey": "followerId",
"through": "Follow"
}
},
"acls": [
{
"accessType": "*",
"principalType": "ROLE",
"principalId": "$everyone",
"permission": "DENY"
},
{
"principalType": "ROLE",
"principalId": "$owner",
"permission": "ALLOW",
"property": "__get__followers"
},
{
"principalType": "ROLE",
"principalId": "$owner",
"permission": "ALLOW",
"property": "__get__followings"
},
{
"principalType": "ROLE",
"principalId": "$owner",
"permission": "ALLOW",
"property": "__get__messages"
}
],
"methods": {}
}
Follow model
{
"name": "Follow",
"base": "PersistedModel",
"idInjection": true,
"options": {
"validateUpsert": true
},
"properties": {},
"validations": [],
"relations": {
"follower": {
"type": "belongsTo",
"model": "Member",
"foreignKey": ""
},
"followee": {
"type": "belongsTo",
"model": "Member",
"foreignKey": ""
}
},
"acls": [],
"methods": {}
}
Example 1
With this data in the database I have the same error when I try to fetch following and followers with member 1.
Erreur non traitée pour la demande GET /api/Members/1/followers?access_token=t0oAVZM2CLJ7XLqQm2zxz8wj3fLmtUATHopDM40WYknLURbiObpVAlSD3DBEIOfv : Error: La relation "member" n'est pas définie pour le modèle Follow
at processIncludeItem (/home/thomas/Bureau/Projet/Project/node_modules/loopback-datasource-juggler/lib/include.js:289:10)
at /home/thomas/Bureau/Projet/Project/node_modules/loopback-datasource-juggler/lib/include.js:180:5
at /home/thomas/Bureau/Projet/Project/node_modules/async/dist/async.js:3025:16
at eachOfArrayLike (/home/thomas/Bureau/Projet/Project/node_modules/async/dist/async.js:940:9)
at eachOf (/home/thomas/Bureau/Projet/Project/node_modules/async/dist/async.js:990:5)
at Object.eachLimit (/home/thomas/Bureau/Projet/Project/node_modules/async/dist/async.js:3089:3)
at Function.Inclusion.include (/home/thomas/Bureau/Projet/Project/node_modules/loopback-datasource-juggler/lib/include.js:179:9)
at /home/thomas/Bureau/Projet/Project/node_modules/loopback-connector-postgresql/node_modules/loopback-connector/lib/sql.js:1203:44
at /home/thomas/Bureau/Projet/Project/node_modules/loopback-datasource-juggler/lib/observer.js:172:22
at doNotify (/home/thomas/Bureau/Projet/Project/node_modules/loopback-datasource-juggler/lib/observer.js:99:49)
at PostgreSQL.ObserverMixin._notifyBaseObservers (/home/thomas/Bureau/Projet/Project/node_modules/loopback-datasource-juggler/lib/observer.js:122:5)
at PostgreSQL.ObserverMixin.notifyObserversOf (/home/thomas/Bureau/Projet/Project/node_modules/loopback-datasource-juggler/lib/observer.js:97:8)
at cbForWork (/home/thomas/Bureau/Projet/Project/node_modules/loopback-datasource-juggler/lib/observer.js:162:14)
at /home/thomas/Bureau/Projet/Project/node_modules/loopback-connector-postgresql/node_modules/loopback-connector/lib/sql.js:428:7
at Query.<anonymous> (/home/thomas/Bureau/Projet/Project/node_modules/loopback-connector-postgresql/lib/postgresql.js:162:7)
at Query.handleReadyForQuery (/home/thomas/Bureau/Projet/Project/node_modules/pg/lib/query.js:124:10)
Example 2
With this data in the database here is the result when I try to fetch followers with member 1.
I don't understand why i'm not able to fetch data in these two examples. BTW i'm using PostgreSQL. Thanks.
You need to fix relations in Follow model according to Member.
{
"name": "Follow",
"base": "PersistedModel",
"idInjection": true,
"options": {
"validateUpsert": true
},
"properties": {},
"validations": [],
"relations": {
"follower": {
"type": "belongsTo",
"model": "Member",
"foreignKey": "followeeId"
},
"followee": {
"type": "belongsTo",
"model": "Member",
"foreignKey": "followerId"
}
},
"acls": [],
"methods": {}
}
And in member.json
...
"followers": {
"type": "hasMany",
"model": "Member",
"foreignKey": "followeeId",
"keyThrough": "followerId",
"through": "Follow"
},
"followings": {
"type": "hasMany",
"model": "Member",
"foreignKey": "followerId",
"keyThrough": "followeeId",
"through": "Follow"
}
...
Related
I have a student model,a favorite model and media models eg music,video etc. I want to implement hasManyThrough ploymorphic relation in which the through model is favorite and then stores these favorites in favorite table in my case mongoDB. Am using loopback3 and its documentation isn't clear about this topic.Any lead?
Your models would look like this:
common/models/student.json
{
"name": "Student",
"base": "User",
"idInjection": true,
"options": {
"validateUpsert": true
},
"properties": {
},
"validations": [],
"relations": {
"favorites": {
"type": "hasMany",
"model": "Favorite",
"foreignKey": "studentId"
},
"videos": {
"type": "hasMany",
"model": "Video",
"foreignKey": "studentId",
"through": "Favorite",
"keyThrough": "favoriteId"
},
"musics": {
"type": "hasMany",
"model": "Music",
"foreignKey": "studentId",
"through": "Favorite",
"keyThrough": "favoriteId"
}
},
"acls": [],
"methods": {}
}
common/models/video.json
{
"name": "Video",
"base": "PersistedModel",
"idInjection": true,
"options": {
"validateUpsert": true
},
"properties": {
},
"validations": [],
"relations": {
"favorites": {
"type": "hasMany",
"model": "Favorite",
"foreignKey": "videoId"
},
"students": {
"type": "hasMany",
"model": "Student",
"foreignKey": "videoId",
"through": "Favorite",
"keyThrough": "studentId"
}
},
"acls": [
],
"methods": {}
}
common/models/favorite.json
{
"name": "Favorite",
"base": "PersistedModel",
"idInjection": true,
"options": {
"validateUpsert": true
},
"properties": {
},
"validations": [],
"relations": {
"student": {
"type": "belongsTo",
"model": "Student",
"foreignKey": "studentId"
},
"video": {
"type": "belongsTo",
"model": "Video",
"foreignKey": "videoId"
},
"music": {
"type": "belongsTo",
"model": "Music",
"foreignKey": "musicId"
}
},
"acls": [],
"methods": {}
}
Then, you simply need to POST a new Favorite item with the attributes studentId and videoId to add the new relation.
EDIT: Added music.json
common/models/music.json
{
"name": "Music",
"base": "PersistedModel",
"idInjection": true,
"options": {
"validateUpsert": true
},
"properties": {
},
"validations": [],
"relations": {
"favorites": {
"type": "hasMany",
"model": "Favorite",
"foreignKey": "musicId"
},
"students": {
"type": "hasMany",
"model": "Student",
"foreignKey": "musicId",
"through": "Favorite",
"keyThrough": "studentId"
}
},
"acls": [
],
"methods": {}
}
I'm currently evaluating loopback.io for developing the API portion of a new project, and I'm having problems with setting the correct ACL entries.
What I wish to accomplish is given an auth token, the GET endpoints should only return objects owned by the user. For example, a request to /Shows?access_token=xxxxxx should return only objects owned by the user.
Below is my shows.json file, and my User model is named Podcaster. Any help would be appreciated.
{
"name": "Show",
"base": "PersistedModel",
"idInjection": true,
"options": {
"validateUpsert": true
},
"properties": {
"title": {
"type": "string",
"required": true
},
"description": {
"type": "string"
}
},
"validations": [],
"relations": {
"episodes": {
"type": "hasMany",
"model": "Episode",
"foreignKey": ""
},
"podcaster": {
"type": "belongsTo",
"model": "Podcaster",
"foreignKey": ""
}
},
"acls": [
{
"accessType": "WRITE",
"principalType": "ROLE",
"principalId": "$authenticated",
"permission": "ALLOW",
"property": "create"
},
{
"accessType": "*",
"principalType": "ROLE",
"principalId": "$owner",
"permission": "ALLOW"
},
{
"accessType": "*",
"principalType": "ROLE",
"principalId": "$everyone",
"permission": "DENY"
}
],
"methods": {}
}
It's not related to ACL's.
You want to change the business logic of the method. So the best practice is that you create a new method for getting shows owning by current user.
If you want to work your current owner ACl, you need to create a relation between user and show, and set ownerId in the show model.
{
"name": "Show",
"base": "PersistedModel",
"idInjection": true,
"options": {
"validateUpsert": true
},
"properties": {
"title": {
"type": "string",
"required": true
},
"description": {
"type": "string"
},
"description": {
"type": "string"
}
"ownerId": {
"type": "object"
}
},
"validations": [],
"relations": {
"owner": {
"type": "belongsTo",
"model": "user",
"foreignKey": "ownerId"
},
....
Premise
Pretty short and simple. In my testing/learning environment for StrongLoop, I have set up two models: CoffeeShop and Person. Persons can have many "employers", and CoffeeShops can have many "employees". This relationship is maintained by a "hasMany"/"through" type relationship on both the CofeeShop and Person models.
Problem
When querying either model through the REST API, an include filter always returns an empty array for the associated relation, even if relations exist. In other words, the API call
http://localhost:3000/api/CoffeeShops/67/employees
works as expected, but
GET: http://localhost:3000/api/CoffeeShops/67/?filter={"include":["employees"]}
Does not.
Could anyone help me figure out why this is? I've attached pictures and the .json model definitions files as well.
// /common/models/coffee-shop.json
{
"name": "CoffeeShop",
"base": "PersistedModel",
"idInjection": true,
"options": {
"validateUpsert": true
},
"properties": {
"name": {
"type": "string",
"required": true
},
"city": {
"type": "string",
"required": true
},
"numberEmployees": {
"type": "number"
},
"ownerId": {
"type": "number"
},
"isSmallBusiness": {
"type": "boolean"
}
},
"validations": [],
"relations": {
"owner": {
"type": "belongsTo",
"model": "Person",
"foreignKey": ""
},
"employees": {
"type": "hasMany",
"model": "Person",
"foreignKey": "employerId",
"through": "CoffeeShopPersonEmployeeEmployer"
}
},
"acls": [],
"methods": {}
}
// /omon/models/person.json
{
"name": "Person",
"plural": "Persons",
"base": "PersistedModel",
"idInjection": true,
"options": {
"validateUpsert": true
},
"properties": {
"name": {
"type": "string",
"required": true
},
"age": {
"type": "number"
}
},
"validations": [],
"relations": {
"shops": {
"type": "hasMany",
"model": "CoffeeShop",
"foreignKey": "ownerId"
},
"employers": {
"type": "hasMany",
"model": "CoffeeShop",
"foreignKey": "employeeId",
"through": "CoffeeShopPersonEmployeeEmployer"
}
},
"acls": [],
"methods": {}
}
// /common/models/coffee-shop-person-employee-employer.json
{
"name": "CoffeeShopPersonEmployeeEmployer",
"base": "PersistedModel",
"idInjection": true,
"options": {
"validateUpsert": true
},
"properties": {},
"validations": [],
"relations": {
"person": {
"type": "belongsTo",
"model": "Person",
"foreignKey": "employeeId"
},
"coffeeShop": {
"type": "belongsTo",
"model": "CoffeeShop",
"foreignKey": "employerId"
}
},
"acls": [],
"methods": {}
}
Images of REST requests
in your CoffeeShopPersonEmployeeEmployer Model:
add foreign keys properties:
"properties": {
"CoffeeShopId": {
"type": "number",
"required": true
},
"PersonId": {
"type": "number",
"required": true
}
}
and ajust the relations :
"relations": {
"person": {
"type": "belongsTo",
"model": "Person",
"foreignKey": "PersonId"
},
"coffeeShop": {
"type": "belongsTo",
"model": "CoffeeShop",
"foreignKey": "CoffeeShopId"
}
}
I´m using the API explorer of loopback to create a model with the following parameters:
{
"name": "string",
"last_name": "string",
"phone": 0,
"is_invited": true,
"realm": "string",
"username": "string",
"credentials": {},
"challenges": {},
"email": "string",
"emailVerified": true,
"status": "string",
"created": "2016-06-03",
"lastUpdated": "2016-06-03",
"id": 0
}
However, The server is always returning a 500 invalid Date error:
{
"error": {
"name": "Error",
"status": 500,
"message": "Invalid date: Invalid Date",
"stack": "Error: Invalid date: Invalid Date\n at DateType }
}
This is my model for reference. It inherits the User model of Loopback.
{
"name": "ExeboardUser",
"base": "User",
"idInjection": true,
"options": {
"validateUpsert": true
},
"properties": {
"name": {
"type": "string",
"required": true
},
"last_name": {
"type": "string"
},
"phone": {
"type": "number",
"required": true
},
"is_invited": {
"type": "boolean",
"required": true
}
},
"validations": [],
"relations": {
"boards": {
"type": "hasMany",
"model": "Board",
"foreignKey": "exeboardUserId",
"through": "ExeboardUserBoard"
}
},
"acls": [
{
"principalType": "ROLE",
"principalId": "$everyone",
"permission": "ALLOW",
"property": "logout"
}
],
"methods": {
}
}
Can anyone tell me what´s the problem with the date? I think it is correctly formated because it´s the default parameters that the explorer generates.
Don't know if you are interested in the answer, but I recently started working with loopback and got the same error as you, the date format that was accepted by the server is like this 2017-01-06T23:58:10.000Z
Hope it helps someone.
Ps.: if the date is not required by the model, don't even send it, not even with "null" or "" value, it will throw a 500 status error.
The correct date format is : 2017-10-12T10:31:37.925Z
And If you want to add fields of dateCreated and dateUpdate, Then use date mixin loopback-ds-timestamp-mixin
Install mixin with
npm i loopback-ds-timestamp-mixin --save
Add the mixins property to your server/model-config.json:
{
"_meta": {
"sources": [
"loopback/common/models",
"loopback/server/models",
"../common/models",
"./models"
],
"mixins": [
"loopback/common/mixins",
"../node_modules/loopback-ds-timestamp-mixin",
"../common/mixins"
]}
}
And in your model:
{
"name": "ExeboardUser",
"base": "User",
"idInjection": true,
"options": {
"validateUpsert": true
},
"mixins": {
"TimeStamp" : true
},
"properties": {
"name": {
"type": "string",
"required": true
},
"last_name": {
"type": "string"
},
"phone": {
"type": "number",
"required": true
},
"is_invited": {
"type": "boolean",
"required": true
}
},
"validations": [],
"relations": {
"boards": {
"type": "hasMany",
"model": "Board",
"foreignKey": "exeboardUserId",
"through": "ExeboardUserBoard"
}
},
"acls": [
{
"principalType": "ROLE",
"principalId": "$everyone",
"permission": "ALLOW",
"property": "logout"
}
],
"methods": {
}
}
When dealing with stringified params you should send the date value as a string in simplified extended ISO format in your query filter.
Here is an example of how you can do this in a very simple way using toISOString method:
const dataValue = new Date('10 May 2018 19:30 UTC');
console.log(dataValue.toISOString());
// output: 2018-05-10T19:30:00.000Z
I have a model "MyUser" inheriting from loopback's "User" model. Now, I don't want this model to expose the password property, so I went and read the docs:
http://docs.strongloop.com/display/public/LB/Model+definition+JSON+file#ModeldefinitionJSONfile-Excludepropertiesfrombasemodel
and
http://docs.strongloop.com/display/public/LB/Model+definition+JSON+file#ModeldefinitionJSONfile-Hiddenproperties
However, this doesn't seem to be working for some reason. I leave some code here:
{
"name": "MyUser",
"plural": "myusers",
"base": "User",
"idInjection": true,
"options": {
"validateUpsert": true
},
"properties": {
"password": null,
"firstName": {
"type": "string"
},
"lastName": {
"type": "string"
}
},
"validations": [],
"relations": {
"cars": {
"type": "hasMany",
"model": "Car"
}
},
"acls": [
{
"accessType": "*",
"principalType": "ROLE",
"principalId": "$everyone",
"permission": "ALLOW"
}
],
"methods": []
}
Thanks in advance.
From your example it appears like you are excluding the password property instead of just hiding it. The Hidden property would look more like this as per the example you referenced:
"properties": {
...
"password": {
"type": "string",
"required": true
},
...
"hidden": ["password"],
...