Falcor Router not resolving $ref - falcor

I've got the following paths defined on my router:
getProjectById[{keys:ids}][{keys:props}]
projects[{ranges:ranges}][{keys:props}]
On client I'm able to successfully retrieve individual projects with the following query:
model.get(
['getProjectById', 'ffd38a56-cca2-11e5-9e6a-695c9890612f', 'name'],
['getProjectById', 'ffd38a55-cca2-11e5-9e6a-695c9890612f', 'name']).then((data) => {
console.log('valid json response ->', data);
});
The 'projects' route returns a reference to each individual project, yet when I make the following request I get undefined as my response:
model.get(['projects', { from: 0, to: 2}, ['name', 'overview']]).then((data) => {
console.log('response is undefined ->', data);
});
The server endpoint returns a promise, when that finally resolves it contains the following array of paths:
[
{ path: ['projects', 0], value: { $ref(['getProjectById', 'ffd38a56-cca2-11e5-9e6a-695c9890612f'] }},
{ path: ['projects', 1], value: { $ref(['getProjectById', 'ffd38a55-cca2-11e5-9e6a-695c9890612f'] }},
{ path: ['projects', 2 ], value : { $atom(undefined) }
]
According to the docs, this should perform a secondary hit on 'getProjectById' route passing in the array of identifiers, but this never gets triggered.

I had similar problem, maybe it will help.
I will give an example, how I've solved it in the past:
route: 'articlesById[{keys}]["_id","title"]',
First route, that contains the $ref (not working):
route: 'articles[{integers}]["title"]',
get: (pathSet) => {
// striped
let articleRef = $ref(['articlesById', currentMongoID]);
return {
path: ['articles', index],
value: articleRef
};
}
FIX:
Delete the ["title"] from the articles route, so the new working is code:
route: 'articles[{integers}]',
get: (pathSet) => {
// striped
let articleRef = $ref(['articlesById', currentMongoID]);
return {
path: ['articles', index],
value: articleRef
};
}
As you can see I've deleted the ["title"] above... you must also make sure that in the articlesById, you have this "title" in place when returning the data so:
{
route: 'articlesById[{keys}]["_id","title"]',
// striped
articleResObj.title = "WE HAVE TITLE HERE"; // make sure of this when returning
results.push({
path: ['articlesById', currentIdString],
value: articleResObj
});

Related

Falcor - HTTPDataSource to post Json

Is it possible to post a Json file using the falcor.browser's model? I have used the get method in it. Below is what I require, but it is not working.
<script src="./js/falcor.browser.js"></script>
function registerUser() {
var dataSource = new falcor.HttpDataSource("http://localhost/registerUser.json");
var model = new falcor.Model({
source: dataSource
});
var userJson = {"name":"John","age":"35","email":"john#abc.com"};
model.
set(userJson).
then(function(done){
console.log(done);
});
This is the server.js code:
app.use('/registerUser.json', falcorExpress.dataSourceRoute(function (req, res) {
return new Router([
{
route: "rating",
get: function() {
// Post call to external Api goes here
}
}
]);
}));
A few things:
The Model's set() method takes 1+ pathValues, so reformat your userJson object literal into a set of pathValues. Something like:
model.
set(
{ path: ['users', 'id1', 'name'], value: 'John' },
{ path: ['users', 'id1', 'age'], value: 35 },
{ path: ['users', 'id1', 'email'], value: 'john#abc.com' }
).
then(function(done){
console.log(done);
});
Second, your router must implement set handlers to correspond to the paths you are trying to set. These handlers should also return pathValues:
new Router([
{
route: 'users[{keys:ids}]["name", "age", "email"]',
set: function(jsonGraph) {
// jsonGraph looks like { users: { id1: { name: "John", age: 35, email: "john#abc.com" }
// make request to update name/age/email fields and return updated pathValues, e.g.
return [
{ path: ['users', 'id1', 'name'], value: 'John' },
{ path: ['users', 'id1', 'age'], value: 35 },
{ path: ['users', 'id1', 'email'], value: 'john#abc.com' },
];
}
}
]);
Given that your DB request is likely asynchronous, your route get handler will have to return a promise or observable. But the above should work as a demonstration.
Edit
You can also use route pattern matching on the third path key if the number of fields gets large, as was demonstrated above on the second id key.
{
route: 'users[{keys:ids}][{keys:fields}]',
set: function(jsonGraph) {
/* jsonGraph looks like
{
users: {
id1: { field1: "xxx", field2: "yyy", ... },
id1: { field1: "xxx", field2: "yyy", ... },
...
}
}
*/
}
}

Using the Javascript Fetch API with Hapi

I created a simple API with Hapi that has a route I can POST to, which looks like this:
server.route({
method: "POST",
path: "/hello",
handler: function(request, reply) {
// It doesn't ever get to here
return reply({hello: request.payload.name});
},
config: {
validate: {
payload: {
name: Joi.string().required()
}
}
}
});
I can successfully send a POST request to this path in Postman:
It returns the expected response. But, when I use this piece of Javascript to send the request:
fetch("http://localhost:1111/hello", {
mode: "cors"
body: {name: "John Doe"}
}).then(() => {
console.log("yay! it worked");
});
This fails, and says "value" must be an object.
It turns out, I just needed to stringify the JSON first, and then it worked:
fetch("http://localhost:1111/hello", {
mode: "cors"
body: JSON.stringify({name: "John Doe"})
}).then(() => {
console.log("yay! it worked");
});

Vue-Resource, can't get this.$http.post working in Vue instance

I am trying to post some data usng this.$http.post and I could not figure out how to pass in the data through the route api..
new Vue({
el: '#root',
data: {
newName: '',
nameList: []
},
methods: {
addName(){
this.nameList = this.nameList.concat(this.newName);
var name = this.newName;
this.newName = '';
this.$http.post('/api/name', {name: name}).then((response) => {
console.log(response.message);
});
}
},
mounted(){
this.$http.get('/api/name').then((response) => {
this.nameList= this.nameList.concat(JSON.parse(response.body));
console.log(this.nameList);
});
}
});
It is not very clear, what is the exact issue, here, what exact API you are trying to hit.
If you are trying to hit: /api/name/:someName, you can do following
this.$http.post('/api/name/'+name ).then((response) => {
console.log(response.message);
});
If you are trying to hit: /api/:someName with payload, you can do following
this.$http.post('/api/' + name, {name: name}).then((response) => {
console.log(response.message);
});
Let me know if it helps.

how to implement mutation responses on a local falcor Model dataset

Given that I have an example Model:
var model = new falcor.Model({
cache: {
userById: {
"1": {
name: "User",
email: "user#email.com"
}
},
users: {
current: null
}
}
});
This is a local model that I'm using for testing purposes, and I would like to implement it on a call to users.login so the user so that I can call:
model.call(['users', 'login'], ['user', 'password'])
I realized that if I do this:
var model = new falcor.Model({
cache: {
userById: {
"1": {
name: "User",
email: "user#email.com"
}
},
users: {
current: null,
login: function(user, password) {
console.log('this code is reached', user, password);
// what to return in order to mutate model?
}
},
}
});
When I do the call it gets there, but I can't figure out how to mutate the model as part of the response; on the server side we return the paths with values and invalidates, and it just works, but here I tried:
// trying returning as a jsonGraph response, don't work
login: function() {
return {
jsonGraph: {
users: {
current: {$type: "ref", value: ['userById', '1']}
}
},
paths: [['users', 'current']]
}
}
// trying returning as a path set mutation list, don't work
login: function() {
return [{path: ['users', 'current'], value: {$type: "ref", value: ['userById', '1']}}]
}
// trying force call to set on the model, don't work
login: function() {
this.set([
{path: ['users', 'current'], value: {$type: "ref", value: ['userById', '1']}}
])
}
// trying using ModelResponse, got an example on some external sources, don't work
login: funtion() {
return new ModelResponse((observer) => {
observer.onNext({
jsonGraph: {
users: {
current: {$type: "ref", value: ['userById', '1']}
}
},
paths: [['users', 'current']]
});
observer.onCompleted();
});
}
Now I don't know what else to try; I need a simple way to declare mutations after a call into a local model, if you know how to solve this, please let me know here.
Thanks.
The client model cache only supports JSONGraph, which b/c it is essentially just JSON with some conventions, doesn't support functions. So, when working with a falcor model cache and no dataSource/middle tier router, it is not possible to implement calls.
This can be kind of annoying when prototyping/testing, as a router is conceptually more difficult than a simple JSON cache object. I ran into this a while ago, so I wrote a dataSource module to support it: falcor-local-datasource. The dataSource is initialized with a graph object that does support function nodes, and as with your above examples, will mutate the graph based on the function's returned JSONGraphEnvelope or an array of PathValues.

How to pass a Hash to Grape API method?

I'm having problems with the Grape gem and the parameters validation.
The idea behind this is to create a complex entity using nested attributes through an API service.
I have a method to create a trip, trip have many destinations and i want to pass that destinations using a hash (using the accepts_nested_attributes_for helper).
I have this grape restriction over the parameter:
requires :destinations, type: Hash
And I'm trying to send something like this:
{ destinations => [
{ destination: { name => 'dest1'} },
{ destination: { name => 'dest2'} },
{ destination: { name => 'dest3'} }
]}
In order to build something like the structure below inside the method and get the trip created:
{ trip: {
name: 'Trip1', destinations_attributes: [
{ name: 'dest1' },
{ name: 'dest2' },
{ name: 'dest3' }
]
}}
I'm using POSTMAN chrome extension to call the API method.
Here's a screen capture:
If someone can help me i would be very grateful.
By the looks of what you are trying to send, you need to change the Grape restriction, because destinations is an Array, not a Hash:
requires :destinations, type: Array
You don't need the "destination" hash when sending the request:
{ destinations => [
{ name => 'dest1', other_attribute: 'value', etc... },
{ name => 'dest2', other_attribute: 'value', etc... },
{ name => 'dest3', other_attribute: 'value', etc... }
]}
This creates an Array of hashes.
In order to send this through POSTMAN, you'll need to modify that destinations param your sending and add multiple lines in POSTMAN. Something like:
destinations[][name] 'dest1'
destinations[][other_attribute] 'value1'
destinations[][name] 'dest2'
destinations[][other_attribute] 'value2'
destinations[][name] 'dest3'
destinations[][other_attribute] 'value3'
Hope this answers your questions. Let me know if this is what you were looking for.

Resources