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
Related
Why my database has field __data that exactly copying the real data but wouldn't update if the data is changed?
Here is the example of the data :
{
"id": ObjectId("600ffdf0317f9617960b7df6"),
"userId" : "bf959bb8-78a6-426b-b372-cf5a1f9ef731",
"name": "Product 1",
"isActive": true,
"createdAt": ISODate("2021-05-26 11:33:04.992Z"),
"updatedAt": null,
"__data": {
"id": "600ffdf0317f9617960b7df6",
"userId" : "bf959bb8-78a6-426b-b372-cf5a1f9ef731",
"name": "Product 1",
"isActive": true,
"createdAt": ISODate("2021-05-26 11:33:04.992Z"),
"updatedAt": null,
},
}
when I update the data lets say, {"name": "Product 1 New"}, but the "__data.name" still "Product 1"
The problem is when I get the data using find() or findById(), the result is showing "Product 1" which is get from the __data instead of the real data.
I'm using loopback v3 and using mongodb for the database.
Below is my schema for product.
product.json
{
"name": "products",
"base": "PersistedModel",
"plural": "products",
"idInjection": true,
"options": {
"validateUpsert": true
},
"properties": {
"id": {
"type": "string",
"id": true
},
"userId": {
"type": "string"
},
"name": {
"type": "object"
},
"isActive": {
"type": "boolean",
"default": false
},
"createdAt": {
"type": "date",
"default": "$now"
},
"updatedAt": {
"type": "date",
"default": "$now"
},
},
"validations": [],
"relations": {
"user": {
"type": "belongsTo",
"model": "reseller",
"foreignKey": "userId"
}
},
"acls": [
],
"scope": {
"order": ["createdAt DESC"]
},
"methods": {}
}
How to solve this?
I want to get the response is the real data which is the updated one, and how to avoid to have field __data?
In case somebody stumbled on this even though LB3 is pretty much dead and IBM is trying to kill off LB4.
My problem was the difference between update() and updateAll(), updateAll() seem to add the data object in mongodb not sure why or how if change to update() is should be fine.
Is there any way to have hook which is checkin that has model attribute public and is it true? If it's true, access token is not required? At the moment I have implemented custom endpoints. But is there some other ways?
I have model where is public attribute, like this:
{
"name": "Model",
"plural": "model",
"base": "PersistedModel",
"idInjection": false,
"options": {
"validateUpsert": true
},
"properties": {
"uuid": {
"type": "string",
"defaultFn": "uuid",
"id": true
},
"orderNumber":{
"type":"number"
},
"public":{
"type":"boolean",
},
"roles": {
"type": "object",
"dataType":"longtext"
},
"groupId": {
"type": "string"
},
"created": {
"type": "date",
"required": true,
"defaultFn": "now"
},
"updated": {
"type": "date",
"required": true,
"defaultFn": "now"
}
},
"validations": [],
"relations": {
},
"acls": [{
"accessType": "*",
"principalType": "ROLE",
"principalId": "$unauthenticated",
"permission": "DENY"
}],
"methods": {},
"scope": {
},
"mixins": {
}
}
You could achieve that by creating a dynamic role called accessiblePublic for example.
Next, in the ACL I would define that this role has access to the endpoint.
Then I would resolve that role dependently on the model that is in the context.
I recommend to read about dynamic roles (and the example there) in the Docs: Dynamic Roles
How to do the relation to match with an array of data in loopback
For e.g
My Models
// Regions model
{
"name": "regions",
"base": "PersistedModel",
"idInjection": true,
"options": {
"validateUpsert": true
},
"properties": {
"title": {
"type": "string",
"required": true
},
"images": {
"type": [
{
"target_id": {
"type": "string"
}
}
]
},
},
"validations": [],
"relations": {},
"acls": [],
"methods": {}
}
// Images model
{
"name": "images",
"base": "PersistedModel",
"idInjection": true,
"options": {
"validateUpsert": true
},
"properties": {
"name": {
"type": "string",
"required": true
},
"url": {
"type": "string",
"required": true
}
},
"validations": [],
"relations": { },
"acls": [],
"methods": {}
}
Expected output:
[
{
"title": "Region 1",
"field_images": [{
"name": "Image 2",
"url": "/media/image-1600x650.jpg",
},{
"name": "Image 1",
"url": "/media/image-1600x650.jpg",
}]
} ]
Assuming that the relationship is HasMany
{
"name": "regions",
"base": "PersistedModel",
...
"relations": {
"images": {
"type": "hasMany",
"model": "images",
"foreignKey": "title", //region title
}
}
...
}
A relationship is defined between two models. So, I highly doubt you would get the images inside an array (if you want to define a relationship between them).
But on loopback you can use separate APIs to retrieve the field_images instead of getting it as an array.
For example - you could retrieve the images like this
region.images([filter],
function(err, images) {
...
});
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"
},
....
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"],
...