As of April 12th, you must go to Progress SupportLink to create new support cases or to access existing cases. Please, bookmark the SupportLink URL and use the new portal to contact the support team.
I have created a custom endpoint and it is supposed to return 10 kinvey entities just like KCSLinkedAppStore queries. However I get raw JSON objects that are not actual Kinvey Entities.
Please help as I think it's utterly important to be able to receive Kinvey entities from calling an endpoint.
activityCollection.find({"fromUser._id":forUserId, "type": "follow", "content" : "accepted"}, function (err, docs) {
if (err) {
logger.error('Query failed: '+ err);
response.error(err);
} else {
response.body = docs; // these should be Kinvey Entities, but instead it's a raw JSON
response.complete(200);
}
});
Best Answer
P
Pranav J
said
about 7 years ago
Grisha,
I have confirmed this with the engineering team.
Custom Endpoints are not attached to an Entity class, for that reason we don’t provide a built-in solution in this case. You can definitely create an init method (as discussed earlier) or a custom parser for this scenario, or use an object mapper library of your choice.
You can also explore the 3.x version of the SDK where it would be a little easier to do the conversion since there is a better object mapping support built into the library. http://devcenter.kinvey.com/ios-v3.0/downloads#
Ignore previous code snippet, This is the code I am using :
activityCollection.find({"fromUser._id":forUserId, "type": "follow", "content" : "accepted"}, function (err, docs) {
if (err) {
logger.error('Query failed: '+ err);
response.error(err);
} else {
var activities = []
for (doc in docs) {
activities.push(modules.kinvey.entity(doc));
}
response.body = activities; // these should be Kinvey Entities, but instead it's a raw JSON
response.complete(200);
}
});
P
Pranav J
said
about 7 years ago
Grisha,
If you add the following logger statements at relevant places in your code, can you let me know their outputs?
logger.info(modules.kinvey.entity(doc));
logger.info(activities);
How it differs from the expected output?
Thanks,
Pranav
Kinvey Support
G
Grisha Gevorkyan
said
about 7 years ago
var activities = [];
for (var i = 0; i < docs.length; i++) {
activities.push(modules.kinvey.entity(docs[i]));
lg.info(modules.kinvey.entity(docs[i]));
}
lg.info("____");
lg.info(activities);
response.body = activities;
response.complete(200);
This outputs following:
[ { "_id":"56b336e67dbaabeb04014204", "author":{ "_type":"KinveyRef", "_id":"55b3cf59eaf8fd4a0c024038", "_collection":"user" }, "details":"Dear All Students, \nToday we will be showing an exhibition of work from our WSA 2nd year Marketing students! The event will comprise of work highlighting gender neutrality and androgynous styles in Fashion!\n\nPlease come along and check it out!\n", "access":"public", "authorId":"55b3cf59eaf8fd4a0c024038", "pictureId":"cb7bdf00-2097-47ab-9ae9-6bfb7102bda5", "date":"ISODate(\"2016-02-04T13:00:00.000Z\")", "_acl":{ "creator":"55b3cf59eaf8fd4a0c024038" }, "createdAt":"ISODate(\"2016-03-15T01:08:49.706Z\")", "_kmd":{ "lmt":"2016-07-02T00:58:20.715Z", "ect":"2016-02-04T11:32:54.417Z" }, "name":"WSA ART EXHIBITION" }, { "_id":"56b337ca7540b68d6d00c59e", "author":{ "_type":"KinveyRef", "_id":"55b3cf59eaf8fd4a0c024038", "_collection":"user" }, "details":"Welcome all. This week we are holding an event hosted by RAG our charity segment of SUSU! We are currently taking donations for a range of good causes so start February with some good KARMA and donate generously! \n\nLove,\n\nAnjit (Student Union Vice President)", "access":"public", "authorId":"55b3cf59eaf8fd4a0c024038", "pictureId":"e39ebe5c-f51a-4083-95c4-49665ace2594", "date":"ISODate(\"2016-02-04T11:33:05.324Z\")", "_acl":{ "creator":"55b3cf59eaf8fd4a0c024038" }, "createdAt":"ISODate(\"2016-03-15T00:49:31.657Z\")", "_kmd":{ "lmt":"2016-07-02T00:58:20.717Z", "ect":"2016-02-04T11:36:42.340Z" }, "name":"The BIG give! " } ]
"_____"
{ "_id":"56b337ca7540b68d6d00c59e", "author":{ "_type":"KinveyRef", "_id":"55b3cf59eaf8fd4a0c024038", "_collection":"user" }, "details":"Welcome all. This week we are holding an event hosted by RAG our charity segment of SUSU! We are currently taking donations for a range of good causes so start February with some good KARMA and donate generously! \n\nLove,\n\nAnjit (Student Union Vice President)", "access":"public", "authorId":"55b3cf59eaf8fd4a0c024038", "pictureId":"e39ebe5c-f51a-4083-95c4-49665ace2594", "date":"ISODate(\"2016-02-04T11:33:05.324Z\")", "_acl":{
P
Pranav J
said
about 7 years ago
Grisha,
In your custom endpoint you will need to handle that case. You need to query the “user” collection for that author given the _id and then insert the resulting user information in “author” field in the response body. It won’t happen by default, you will need to code it in the custom endpoint.
Thanks, Pranav Kinvey Support
G
Grisha Gevorkyan
said
about 7 years ago
Dear Pranav,
Thank you, but this is not my problem. My problem is that when I do following in my iOS code:
let store = KCSLinkedAppdataStore.storeWithOptions([
KCSStoreKeyCollectionName : "Events",
KCSStoreKeyCollectionTemplateClass : Event.self
])
store.queryWithQuery(query, withCompletionBlock: {
(objects:[AnyObject]!, error:NSError!) -> Void in
if (error == nil){
var temp:[Event] = []
for object in objects {
print(object)
temp.append(object as! Event)
}
completionBlock(events: temp, error: nil)
}else{
completionBlock(events: nil, error: error)
}
}, withProgressBlock: nil)
It works normal.
But when I try the same with the endpoint:
KCSCustomEndpoints.callEndpoint(
"get_followed_content",
params: nil,
completionBlock: {
(objects: AnyObject!, error: NSError!) -> Void in
if error == nil {
var temp:[Event] = []
for object in objects {
temp.append(object as! Event)
}
completionHandler(downloadedEventsArray: temp, error: nil)
} else {
print(error)
completionHandler(downloadedEventsArray: [], error: error)
}
}
)
it crashes.
Please have a look at this as it's a major obstacle for my app.
G
Grisha Gevorkyan
said
about 7 years ago
And it crashes always on this line
temp.append(object as! Event)
It fails to cast downloaded object into the KCSPersistable object.
G
Grisha Gevorkyan
said
about 7 years ago
Please help, I really need to get objects from calling endpoint the same way I do from queryWithQuery.
P
Pranav J
said
about 7 years ago
Grisha,
Can you send the definition of your Event class?
Do you see any difference in the outputs (structure of the json) (when you run them from the Kinvey Console)?
Query 1) Output when querying the collection Query 2) Output when executing the custom endpoint
What is the Kid of your app and version of Kinvey SDK you are using?
Thanks, Pranav
Kinvey Support
G
Grisha Gevorkyan
said
about 7 years ago
My definition of Event class:
class Event: NSObject {
var entityId: NSString? //Kinvey entity _id
var author: KCSUser!
var authorId: NSString?
var name: NSString?
var details: NSString?
var pictureId: NSString?
var date: NSDate?
var location: NSString?
var access:NSString?
var createdAt: NSDate?
var hidden:NSString?
var sharedID:NSString?
var metadata: KCSMetadata? //Kinvey metadata, optional
internal override func hostToKinveyPropertyMapping() -> [NSObject : AnyObject]! {
return [
"entityId" : KCSEntityKeyId, //the required _id field
"author" : "author",
"name" : "name",
"details" : "details",
"pictureId" : "pictureId",
"authorId" : "authorId",
"date" : "date",
"location" : "location",
"access" : "access",
"hidden" : "hidden",
"createdAt": "createdAt",
"sharedID" : "sharedID",
"metadata" : KCSEntityKeyMetadata //optional _metadata field
]
}
internal class override func kinveyPropertyToCollectionMapping() -> [NSObject : AnyObject]! {
return [
"author" : KCSUserCollectionName,
]
}
}
The definition of endpoint is:
function onRequest(request, response, modules) {
var lg = modules.logger;
// Get id of user who sent the request
var requestContext = modules.requestContext;
var forUserId = requestContext.getAuthenticatedUserId();
// modules.logger.info(forUserId);
var activityCollection = modules.collectionAccess.collection('Activity');
var eventsCollection = modules.collectionAccess.collection('Events');
var usersCollection = modules.collectionAccess.collection('user');
// Now finding all the users that he is following
activityCollection.find({"fromUser._id":forUserId, "type": "follow", "content" : "accepted"}, function (err, docs) {
if (err) {
lg.error('Query failed: '+ err);
response.error(err);
} else {
if (docs.length === 0) {
response.body = docs;
response.complete(200);
return;
}
var followingUserIds = [];
for (var i = 0; i < docs.length; i++) {
followingUserIds.push(docs[i].toUser._id);
}
// by this moment we should already have following ids
// let's fetch events
eventsCollection.find({ "author._id" : {$in: followingUserIds}}, function (err, docs) {
if (err) {
logger.error('Query failed: '+ err);
response.error(err);
} else {
// Store all event Ids !
if (docs.length === 0) {
response.body = docs;
response.complete(200);
return;
}
var events = [];
// for async loading
var authorsLoaded = 0;
var authorsToLoad = docs.length;
for (var i = 0; i < docs.length; i++) {
var event = modules.kinvey.entity(docs[i]);
usersCollection.find(usersCollection.objectID(event.author._id), function (err, docs) {
if (err) {
lg.error('Query failed: '+ err);
response.error(err);
} else {
if (docs.length > 0) {
authorsLoaded += 1;
var ev = {}
event.author = docs[0];
events.push(event);
if (authorsLoaded == authorsToLoad) {
lg.info("All Loaded");
response.body = events;
response.complete(200);
}
} else {
lg.info("no author found");
return;
}
}
});
}
}
});
}
});
}
Endpoint works perfectly (returns correct JSON) , you don't have to understand the code but basically it finds users that are followed by the request user and loads their events.
Now the result from calling the endpoint is:
{
"_id":"56b337ca7540b68d6d00c59e",
"author":{
"_id":"55b3cf59eaf8fd4a0c024038",
"access":"public",
"pictureId":"9963f249-adf5-4fd2-8c04-b0b2841166f6",
"_messaging":{
"pushTokens":[
{
"token":"d66f9d002ff0f8b630408fa0d411aa3eb5d9ef946b9930cea1986bedf5a09d97",
"platform":"ios",
"arn":"arn:aws:sns:us-east-1:853461911189:endpoint/APNS_SANDBOX/kid_W19oFN4H1l_development/a4383c07-565e-34de-bc5f-1d7891d5b1b9"
},
{
"token":"cb6ea190e8b8829cacf24f063785c082859130f3910e540192d138ed40ddc099",
"platform":"ios",
"arn":"arn:aws:sns:us-east-1:853461911189:endpoint/APNS_SANDBOX/kid_W19oFN4H1l_development/5957aec1-d587-3d3c-b7ff-ed76f09e444a"
}
]
},
"bio":"Studying at Winchester School of Art, Southampton University",
"_push":{
"_devicetokens":[
"d66f9d002ff0f8b630408fa0d411aa3eb5d9ef946b9930cea1986bedf5a09d97"
]
},
"_acl":{
"creator":"55b3cf59eaf8fd4a0c024038"
},
"username":"darren",
"_kmd":{
"lmt":"2016-03-18T19:12:09.099Z",
"ect":"2015-07-25T18:03:05.741Z"
},
"first_name":"Darren Yu",
"salt":"1ab54605-9bf1-4932-bbae-e375fda235df"
},
"details":"Welcome all. This week we are holding an event hosted by RAG our charity segment of SUSU! We are currently taking donations for a range of good causes so start February with some good KARMA and donate generously! \n\nLove,\n\nAnjit (Student Union Vice President)",
"access":"public",
"authorId":"55b3cf59eaf8fd4a0c024038",
"pictureId":"e39ebe5c-f51a-4083-95c4-49665ace2594",
"date":"ISODate(\"2016-02-04T11:33:05.324Z\")",
"_acl":{
"creator":"55b3cf59eaf8fd4a0c024038"
},
"createdAt":"ISODate(\"2016-03-15T00:49:31.657Z\")",
"_kmd":{
"lmt":"2016-07-29T00:32:24.988Z",
"ect":"2016-02-04T11:36:42.340Z"
},
"name":"The BIG give! "
},
The result from querying the collection in console is :
{
"_id":"56b337ca7540b68d6d00c59e",
"author":{
"_type":"KinveyRef",
"_id":"55b3cf59eaf8fd4a0c024038",
"_collection":"user"
},
"details":"Welcome all. This week we are holding an event hosted by RAG our charity segment of SUSU! We are currently taking donations for a range of good causes so start February with some good KARMA and donate generously! \n\nLove,\n\nAnjit (Student Union Vice President)",
"access":"public",
"authorId":"55b3cf59eaf8fd4a0c024038",
"pictureId":"e39ebe5c-f51a-4083-95c4-49665ace2594",
"date":"ISODate(\"2016-02-04T11:33:05.324Z\")",
"_acl":{
"creator":"55b3cf59eaf8fd4a0c024038"
},
"createdAt":"ISODate(\"2016-03-15T00:49:31.657Z\")",
"_kmd":{
"lmt":"2016-03-15T00:49:31.663Z",
"ect":"2016-02-04T11:36:42.340Z"
},
"name":"The BIG give! "
}
But it is only querying in the console, when I call queryWithQuery within the app, it returns relational data ( author of the event) as well.
The crash in the apphappenswhen I try to cast results from endpoint from raw JSON into Event with the following line:
for result in results as! [AnyObject]! {
let event = result as! Event
}
However if the result is from completion block of KCSLinkedAppDataStore.queryWithQuery, same casting works fine.
Therefore I suggest in the first case response is raw JSON and in the second it's a KCSPersistable Object and that there is some private method provided by Kinvey that casts raw JSON into objects that conform KCSPersistable protocol
I don't really want to write that wrapper to handle this case, I consider it would be waste of time. Is there a method provided that can cast raw JSON into KCSPersistable objects, so that calling the endpoint would work the same way as KCSAppdataStore.queryWithQuery .
G
Grisha Gevorkyan
said
about 7 years ago
Also my Kid is kid_W19oFN4H1l
P
Pranav J
said
about 7 years ago
Grisha,
Can you send the definition of your Event class?
Do you see any difference in the outputs (structure of the json) (when you run them from the Kinvey Console)?
Query 1) Output when querying the collection Query 2) Output when executing the custom endpoint
Also, let me know the Kinvey sdk version.
Thanks,
Pranav
Kinvey Support
G
Grisha Gevorkyan
said
about 7 years ago
My replies seem to appear with a big delay, please see my responses above. Also my SDK version is 1.40.7
P
Pranav J
said
about 7 years ago
Grisha,
I was trying to replicate your issue. Are you getting this below error? "Could not cast value of type '__NSCFDictionary' to ‘TestKinvey.Event’"
One way to deal with it to write an init() for the Event class that takes an NSDictionary as a parameter:
and then use that to construct your Events from raw json: let jobrl: Event_Grisha? = Event_Grisha(dict2: obj[0] as! NSDictionary)
But I understand that you want both the methods (using KCSLinkedAppdataStore as well as using KCSCustomEndpoint) to be similar. I am still reviewing this and I will get back to you with more information as soon as possible.
Thanks, Pranav Kinvey Support
G
Grisha Gevorkyan
said
about 7 years ago
Exactly this issue!
I would have done it with initializer (tried it before), however I also need to create KCSMetadata object and I don't know how to construct it and fill it with properties. Also I am intend to reuse these downloaded events, for example user downloads followed content, finds his own event and wants to edit some values in it and save to the server, however if I do it your way, I am not sure what will happen to metadata fields and will it save all other properties properly.
Kinvey already solved this problem somehow constructing these objects and providing them with completion block with KCSLinkedAppDataStore , would it be possible to just tell me how to replicate this way?
Grisha Gevorkyan
I have created a custom endpoint and it is supposed to return 10 kinvey entities just like KCSLinkedAppStore queries. However I get raw JSON objects that are not actual Kinvey Entities.
Please help as I think it's utterly important to be able to receive Kinvey entities from calling an endpoint.
I have confirmed this with the engineering team.
Custom Endpoints are not attached to an Entity class, for that reason we don’t provide a built-in solution in this case. You can definitely create an init method (as discussed earlier) or a custom parser for this scenario, or use an object mapper library of your choice.
You can also explore the 3.x version of the SDK where it would be a little easier to do the conversion since there is a better object mapping support built into the library.
http://devcenter.kinvey.com/ios-v3.0/downloads#
Thanks,
Pranav
Kinvey Support
- Oldest First
- Popular
- Newest First
Sorted by Oldest FirstGrisha Gevorkyan
Ignore previous code snippet,
This is the code I am using :
Pranav J
Grisha,
If you add the following logger statements at relevant places in your code, can you let me know their outputs?
How it differs from the expected output?
Thanks,
Pranav
Kinvey Support
Grisha Gevorkyan
This outputs following:
[
{
"_id":"56b336e67dbaabeb04014204",
"author":{
"_type":"KinveyRef",
"_id":"55b3cf59eaf8fd4a0c024038",
"_collection":"user"
},
"details":"Dear All Students, \nToday we will be showing an exhibition of work from our WSA 2nd year Marketing students! The event will comprise of work highlighting gender neutrality and androgynous styles in Fashion!\n\nPlease come along and check it out!\n",
"access":"public",
"authorId":"55b3cf59eaf8fd4a0c024038",
"pictureId":"cb7bdf00-2097-47ab-9ae9-6bfb7102bda5",
"date":"ISODate(\"2016-02-04T13:00:00.000Z\")",
"_acl":{
"creator":"55b3cf59eaf8fd4a0c024038"
},
"createdAt":"ISODate(\"2016-03-15T01:08:49.706Z\")",
"_kmd":{
"lmt":"2016-07-02T00:58:20.715Z",
"ect":"2016-02-04T11:32:54.417Z"
},
"name":"WSA ART EXHIBITION"
},
{
"_id":"56b337ca7540b68d6d00c59e",
"author":{
"_type":"KinveyRef",
"_id":"55b3cf59eaf8fd4a0c024038",
"_collection":"user"
},
"details":"Welcome all. This week we are holding an event hosted by RAG our charity segment of SUSU! We are currently taking donations for a range of good causes so start February with some good KARMA and donate generously! \n\nLove,\n\nAnjit (Student Union Vice President)",
"access":"public",
"authorId":"55b3cf59eaf8fd4a0c024038",
"pictureId":"e39ebe5c-f51a-4083-95c4-49665ace2594",
"date":"ISODate(\"2016-02-04T11:33:05.324Z\")",
"_acl":{
"creator":"55b3cf59eaf8fd4a0c024038"
},
"createdAt":"ISODate(\"2016-03-15T00:49:31.657Z\")",
"_kmd":{
"lmt":"2016-07-02T00:58:20.717Z",
"ect":"2016-02-04T11:36:42.340Z"
},
"name":"The BIG give! "
}
]
"_____"
{
"_id":"56b337ca7540b68d6d00c59e",
"author":{
"_type":"KinveyRef",
"_id":"55b3cf59eaf8fd4a0c024038",
"_collection":"user"
},
"details":"Welcome all. This week we are holding an event hosted by RAG our charity segment of SUSU! We are currently taking donations for a range of good causes so start February with some good KARMA and donate generously! \n\nLove,\n\nAnjit (Student Union Vice President)",
"access":"public",
"authorId":"55b3cf59eaf8fd4a0c024038",
"pictureId":"e39ebe5c-f51a-4083-95c4-49665ace2594",
"date":"ISODate(\"2016-02-04T11:33:05.324Z\")",
"_acl":{
Pranav J
In your custom endpoint you will need to handle that case. You need to query the “user” collection for that author given the _id and then insert the resulting user information in “author” field in the response body.
It won’t happen by default, you will need to code it in the custom endpoint.
Thanks,
Pranav
Kinvey Support
Grisha Gevorkyan
Dear Pranav,
Thank you, but this is not my problem. My problem is that when I do following in my iOS code:
It works normal.
But when I try the same with the endpoint:
it crashes.
Please have a look at this as it's a major obstacle for my app.
Grisha Gevorkyan
And it crashes always on this line
temp.append(object as! Event)
It fails to cast downloaded object into the KCSPersistable object.
Grisha Gevorkyan
Please help, I really need to get objects from calling endpoint the same way I do from queryWithQuery.
Pranav J
Grisha,
Can you send the definition of your Event class?
Do you see any difference in the outputs (structure of the json) (when you run them from the Kinvey Console)?
Query 1) Output when querying the collection
Query 2) Output when executing the custom endpoint
What is the Kid of your app and version of Kinvey SDK you are using?
Thanks,
Pranav
Kinvey Support
Grisha Gevorkyan
My definition of Event class:
The definition of endpoint is:
Endpoint works perfectly (returns correct JSON) , you don't have to understand the code but basically it finds users that are followed by the request user and loads their events.
Now the result from calling the endpoint is:
The result from querying the collection in console is :
But it is only querying in the console, when I call queryWithQuery within the app, it returns relational data ( author of the event) as well.
The crash in the app happens when I try to cast results from endpoint from raw JSON into Event with the following line:
for result in results as! [AnyObject]! {
let event = result as! Event
}
However if the result is from completion block of KCSLinkedAppDataStore.queryWithQuery, same casting works fine.
Therefore I suggest in the first case response is raw JSON and in the second it's a KCSPersistable Object and that there is some private method provided by Kinvey that casts raw JSON into objects that conform KCSPersistable protocol
I don't really want to write that wrapper to handle this case, I consider it would be waste of time. Is there a method provided that can cast raw JSON into KCSPersistable objects, so that calling the endpoint would work the same way as KCSAppdataStore.queryWithQuery .
Grisha Gevorkyan
Also my Kid is kid_W19oFN4H1l
Pranav J
Grisha,
Can you send the definition of your Event class?
Do you see any difference in the outputs (structure of the json) (when you run them from the Kinvey Console)?
Query 1) Output when querying the collection
Query 2) Output when executing the custom endpoint
Also, let me know the Kinvey sdk version.
Thanks,
Pranav
Kinvey Support
Grisha Gevorkyan
My replies seem to appear with a big delay, please see my responses above. Also my SDK version is 1.40.7
Pranav J
I was trying to replicate your issue. Are you getting this below error?
"Could not cast value of type '__NSCFDictionary' to ‘TestKinvey.Event’"
One way to deal with it to write an init() for the Event class that takes an NSDictionary as a parameter:
init(dict2: NSDictionary)
{
// initialize variables here
entityId = dict2["_id"] as? NSString
name = dict2["name"] as? NSString
details = dict2["details"] as? NSString
…
}
and then use that to construct your Events from raw json:
let jobrl: Event_Grisha? = Event_Grisha(dict2: obj[0] as! NSDictionary)
But I understand that you want both the methods (using KCSLinkedAppdataStore as well as using KCSCustomEndpoint) to be similar. I am still reviewing this and I will get back to you with more information as soon as possible.
Thanks,
Pranav
Kinvey Support
Grisha Gevorkyan
Exactly this issue!
I would have done it with initializer (tried it before), however I also need to create KCSMetadata object and I don't know how to construct it and fill it with properties. Also I am intend to reuse these downloaded events, for example user downloads followed content, finds his own event and wants to edit some values in it and save to the server, however if I do it your way, I am not sure what will happen to metadata fields and will it save all other properties properly.
Kinvey already solved this problem somehow constructing these objects and providing them with completion block with KCSLinkedAppDataStore , would it be possible to just tell me how to replicate this way?
-
Why do I get "Undefined symbols" errors when building with KinveyKit?
-
How do I register push tokens?
-
When using social login, to perform a log-out, do I need to log out of the social network, Kinvey, o
-
How can I assign additional properties to users?
-
Does KinveyKit support 64-bit ARM devices, such as iPhone 5s?
-
Authorization Token Invalid or Expired
-
BOOL and how it is stored in the database.
-
Offline saving throwing errors
-
Custom endpoint not able to form request object
-
Security through business logic
See all 437 topics