How can I put received data from a GRAPHQL endpoint into state so that I can display in my Navbar Component dynamically? - graphql-js

Here is how got the data,Iam still new to Graphql and ReactJS
componentDidMount(){
const query = gql`
{
categories {
name
}
}
`
request('http://localhost:4000/graphql', query).then((data) =>
console.log(data)
and this the data in console:
enter image description here

Related

Meteor and React Native - FileCollection Access

i posted this question some time ago at the FilesCollection Github Repo (https://github.com/veliovgroup/Meteor-Files), but I'll hope to reach out here anyone who is familiar with Meteor and React Native.
My problem is, that I'm not sure how to use a FilesCollection with React Native (RN) and Meteor.
I used the official Meteor guide to set up a RN app: https://guide.meteor.com/react-native.html
So i have access to #meteorrn/core but how is it now possible for me to access a FileCollection.
Usually you would do this with (on a non-RN-web app):
import { FilesCollection } from "meteor/ostrio:files";
export const ImageDB = new FilesCollection(chosenSettings);
where chosenSettings are some settings might be e.g.
const chosenSettings = {
collectionName: "Images",
allowClientCode: false,
onBeforeUpload(file) {
if (file.size <= 10485760 && /png|jpg|jpeg/i.test(file.extension)) {
return true;
}
return "Please upload image, with size equal or less than 10MB";
},
storagePath: `${process.env.PWD}/images`,
};
However, with RN it is not possible to access FilesCollection from meteor/ostrio:files as I don't have any meteor relation here
With other collections I can use Mongo.Collection from #meteorrn/core, however this is not possible with FilesCollection:
const collection = new Mongo.Collection("myCollection");
Any suggestions?
There is no "out-of-the-box" solution, as there is no FilesCollection on the RN client available. However, you could create a workaround strategy using a Meteor method.
Create a publication for the FilesCollection's underlying collection:
server
Meteor.publish('imagesForRN', function () {
return ImageDB.collection.find({}) // note the Mongo.collection is accessible here
})
Create a Method to resolve links:
server
Meteor.methods({
resolveRNLinks ({ ids }) {
return ImageDB.collection
.find({ _id: { $in: ids}})
.map(linkImage);
}
})
const linkImage = function (fileRef) {
const url = Images.link(fileRef, 'original', Meteor.absoluteUrl())
return { _id: fileRef._id, url }
}
Get the URLS of the subscribed docs
This assumes you have subscribed to the Image Collection as shown in the guide.
client
import Meteor from '#meteorrn/core'
const MyComponent = props => {
const { loading, myTodoTasks } = this.props;
useEffect(() => {
const ids = myTodoTasks.map(doc => doc._id)
// note, you should filter those ids, which you have already
// resolved so you only call for the new ones
Meteor.call('resolveRNLinks', { ids }, (err, urls) => {
// store urls in state or ref, depending on your usecase
})
})
}
Resources
https://github.com/TheRealNate/meteor-react-native
https://github.com/veliovgroup/Meteor-Files/blob/master/docs/collection.md
https://github.com/veliovgroup/Meteor-Files/blob/master/docs/link.md

KeystoneJS as back-end with Flutter as front-end

Is it possible/feasible to use KeystoneJS along with a front-end developed in Flutter for web? Would it make sense to do so? Any hint would be appreciated.
Keystonejs is any other backend which provides headless cms capability. You can use this like any other backend using GraphQL client if available in Flutter.
I see Flutter does support http request you can use this feature to call GraphQL using plain http query (http package). example query to get all users from User list
var client = http.Client();
try {
var response = await client.post('https://keystoneproject.com/admin/api',
body: { 'query': 'query { allUsers { id name email isAdmin }}' });
// this gives you result in JSON format `{ data: { allusers { id: "id value", name: "name of user", email: "email of user", isAdmin: false } }
print(await client.get(response.bodyFields['data']));
} finally {
client.close();
}
body should also contain variable field if your query has any parameter (see GraphQL reference on how that work, I don't think that is scope of the answer)

Express - return certain documents with named route parameters using axios

I'm having trouble communicating between the frontend and backend for a selected GET request.
I am using a React frontend with an express/mongoose setup out in the backend.
In the frontend, I do a GET call using axios for:
axios.get('/api/orders/', {
params : {
name: this.props.user.name // user name can be Bob
}
})
And in the backend I'm having a hard time understanding the correct method I would need to do to query the database (example below doesn't work). I found stuff with .select but even then I still can't get it to work:
router.get('/orders', function(req, res) {
Order.find({}).select(req.params).then(function (order) {
res.send(req.params);
})
});
I also tried doing this to see if I can even get the params to send properly and to no demise:
router.get('/orders/:name', function(req, res) {
res.send('client sent :',req.query.name);
});
The orders document model holds objects that house an ordered array and a name (type: String) attached to the object. The Mongoose scheme for the order:
const orderScheme = new Schema({
name : { type : String },
orders : { type : Array}
});
In my MongoDB, I can see all the "Master Orders" send back. Each master order has the name of who submitted it, plus all the orders within (there can be a ton of orders).
What I'm trying to exactly do is pull up all orders that have a certain name. So if I search "TestAccount", I'll get all of bob's orders. I've included an image below:
Any pointers?
Client-side:
axios.get('/api/orders/' + this.props.user.name)
.then(function (response) {
// handle success
console.log(response);
})
.catch(function (error) {
// handle error
console.log(error);
})
You need to handle the Promise when resolved/rejected.
Server-side:
router.get('/orders/:name', function(req, res) {
return Order.find({name: req.params.name}).then(function(orders) {
// return orders when resolved
res.send(orders);
})
.catch(function (error) {
// handle error
console.log(error);
})
});
You did not specify a named route parameter in your route path.
You also aren't accessing the name property by using req.params only.
You should use Model.find() conditions parameter to specify which document[s] you're trying to find. Query.prototype.select() is for filtering document fields.

How to identify unique users with Diagflow

I am trying to make an assistant app and was using the cloud firestore service of firebase to send the response back to my app using webhook as fulfilment. I have used 'session' parameter in request JSON according to this documentation and sending fulfilmentText as response to the user. But whenever user launches the app, a new session is created which I don't want. I simply want, just a single entry for each user in my database so how to achieve that using dialogflow.
In Alexa Skill, we have deviceId as parameter by which we can uniquely identify the user irrespective of the session id but is there any parameter in the dialogflow request JSON. If not, then how to achieve this task without it.
The request JSON I am getting from Dialogflow has a userID in it, so can I use the userId or should I go with userStorage provided the userStorage parameter is not available in the request JSON.
request.body.originalDetectIntentRequest { source: 'google', version: '2', payload: { surface: { capabilities: [Object] },
inputs: [ [Object] ],
user:
{ locale: 'en-US',
userId: 'ABwppHG5OfRf2qquWWjI-Uy-MwfiE1DQlCCeoDrGhG8b0fHVg7GsPmaKehtxAcP-_ycf_9IQVtUISgfKhZzawL7spA' },
conversation:
{ conversationId: '1528790005269',
type: 'ACTIVE',
conversationToken: '["generate-number-followup"]' },
availableSurfaces: [ [Object] ] } }
EDIT : Thank You #Prisoner for the answer but I am unable to send the random ID generated in the response and set in in the payload. Below is the code where I am generating the uuid and storing it in firestore. What I am doing wrong in the below code due to which new uuid is generated for returning user and therefore response is shown as No document found in the database. I suppose I am not sending uuid appropriately. Please help.
exports.webhook = functions.https.onRequest((request, response) => {
console.log("request.body.queryResult.parameters", request.body.queryResult.parameters);
console.log("request.body.originalDetectIntentRequest.payload", request.body.originalDetectIntentRequest.payload);
let userStorage = request.body.originalDetectIntentRequest.payload.user.userStorage || {};
let userId;
console.log("userStorage", userStorage);
if (userId in userStorage) {
userId = userStorage.userId;
} else {
var uuid = require('uuid/v4');
userId = uuid();
userStorage.userId = userId
}
console.log("userID", userId);
switch (request.body.queryResult.action) {
case 'FeedbackAction': {
let params = request.body.queryResult.parameters;
firestore.collection('users').doc(userId).set(params)
.then(() => {
response.send({
'fulfillmentText' : `Thank You for visiting our ${params.resortLocation} hotel branch and giving us ${params.rating} and your comment as ${params.comments}.` ,
'payload': {
'google': {
'userStorage': userStorage
}
}
});
return console.log("resort location", params.resortLocation);
})
.catch((e => {
console.log('error: ', e);
response.send({
'fulfillmentText' : `something went wrong when writing to database`,
'payload': {
'google': {
'userStorage': userStorage
}
}
});
}))
break;
}
case 'countFeedbacks':{
var docRef = firestore.collection('users').doc(userId);
docRef.get().then(doc => {
if (doc.exists) {
// console.log("Document data:", doc.data());
var dat = doc.data();
response.send({
'fulfillmentText' : `You have given feedback for ${dat.resortLocation} and rating as ${dat.rating}`,
'payload': {
'google': {
'userStorage': userStorage
}
}
});
} else {
// doc.data() will be undefined in this case
console.log("No such document!");
response.send({
'fulfillmentText' : `No feedback found in our database`,
'payload': {
'google': {
'userStorage': userStorage
}
}
});
}
return console.log("userStorage_then_wala", userStorage);
}).catch((e => {
console.log("Error getting document:", error);
response.send({
'fulfillmentText' : `something went wrong while reading from the database`,
'payload': {
'google': {
'userStorage': userStorage
}
}
})
}));
break;
}
You have a couple of options, depending on your exact needs.
Simple: userStorage
Google provides a userStorage object which is persisted across conversations when it can identify a user. This lets you store your own identifier when you need to track when a user returns.
The easiest way to do this is to check the userStorage object for the identifier when your webhook is called. If it doesn't exist, create one using something like a v4 UUID and save it in the userStorage object.
If you are using the actions-on-google library, the code might look something like this:
let userId;
// if a value for userID exists un user storage, it's a returning user so we can
// just read the value and use it. If a value for userId does not exist in user storage,
// it's a new user, so we need to generate a new ID and save it in user storage.
if (userId in conv.user.storage) {
userId = conv.user.storage.userId;
} else {
// Uses the "uuid" package. You can get this with "npm install --save uuid"
var uuid = require('uuid/v4');
userId = uuid();
conv.user.storage.userId = userId
}
If you are using the dialogflow library, you can use the above, but you'll need this line first:
let conv = agent.conv();
If you're using the multivocal library, it does all of the above for you and will provide a UserID in the environment under the path User/Id.
If you're handling the JSON directly, and you are using the Dialogflow v2 protocol, you can get the userStorage object by examining originalDetectIntentRequest.payload.user.userStorage in the JSON request object. You'll set the payload.google.userStorage object in the JSON response. The code is similar to the above and might look something like this:
let userStorage = body.originalDetectIntentRequest.payload.user.userStorage || {};
let userId;
// if a value for userID exists un user storage, it's a returning user so we can
// just read the value and use it. If a value for userId does not exist in user storage,
// it's a new user, so we need to generate a new ID and save it in user storage.
if (userId in userStorage) {
userId = userStorage.userId;
} else {
// Uses the "uuid" package. You can get this with "npm install --save uuid"
var uuid = require('uuid/v4');
userId = uuid();
userStorage.userId = userId
}
// ... Do stuff with the userID
// Make sure you include the userStorage as part of the response
var responseBody = {
payload: {
google: {
userStorage: JSON.stringify(userStorage),
// ...
}
}
};
Note the first line of the code - if userStorage doesn't exist, use an empty object. It won't exist until you send a response that includes storing something in it for the first time, which will happen in the last few lines of this code.
Advanced: Account Linking
You can request users to sign in to your Action using Google Sign In. This can be done just using voice for the simplest of cases and would only interrupt the flow the first time.
After this, your Action is given a JWT which contains their Google ID which you can use as their identifier.
If you're using the actions-on-google library, you can get the ID from the decoded JWT with a line such as:
const userId = conv.user.profile.payload.sub;
In the multivocal library, the ID from the decoded JWT is available in the environment under the path User/Profile/sub
Deprecated: Anonymous User ID
You'll see some answers here on StackOverflow that reference an Anonymous User ID. Google has deprecated this identifier, which was not always a reliable way to verify returning users, and will be removing it 1 Jun 2019.
This code is currently still being sent, but this will be removed starting 1 Jun 2019.

Get a single document with Angular 2

I'm following the angular 2 Tutorial of Heroes guide and trying to get and display a single Hero from mongoDb when I go to the hero detail section (as seen in the tutorial). I'm able to find my users (heroes) in mongo running a node backend but not the single hero when accessing that section.
hero.service.ts
//The part that gives me errors.
private heroesUrl = 'http://localhost:8080/admin/users';
constructor(private http: Http) { }
//Works
getHeroes() {
return this.http.get(this.heroesUrl)
.toPromise()
.then(response => response.json() as Hero[])
.catch(this.handleError);
}
//Doesn't work
getHero(_id: number) {
return this.getHeroes()
//How should I work with the _id?
.then(heroes => heroes.find(hero => hero._id === _id));
}
//:note that this worked properly when I had the documents in memory with a mock api. Where the ids initially where numbers.
It seems to me that the id must be numeric:
https://angular.io/docs/ts/latest/tutorial/toh-pt5.html
The /detail/ part of that URL is constant. The trailing numeric id part changes from hero to hero. We need to represent that variable part of the route with a parameter (or token) that stands for the hero's id.
and that the ObjectId I get from mongoDb doesn't work well together with this. If I change the number parameter to be string instead and parse the id to be a string it doesn't work either, and I didn't expect it to either because I don't know what I'm doing at the moment!.
getHero(_id: String)
anyway... When I run my typeScript compiler I get this error:
app/+heroes/hero.service.ts(24,65): error TS2345: Argument of type 'number' is not assignable to parameter of type 'string'.
I don't really understand how this work in angular 2/typeScript, sorry that don't know either exactly what to ask for regarding my problem.
app.routes.ts
const routes: RouterConfig = [
{
path: '',
component: DashboardComponent
},
{
path: 'detail/:id',
component: HeroDetailComponent
},
{
path: 'heroes',
component: HeroesComponent
}
];
My app recognizes the id and sends me to the correct path: http://localhost:8080/detail/5773fbc1383ec4868619f1fa
But whilst on the page no data is found.
Failed to load resource: the server responded with a status of 404 (Not Found)
In my dashboard this is how I navigate to the hero's own route.
export class DashboardComponent implements OnInit {
heroes: Hero [] = [];
constructor(
private router: Router,
private heroService: HeroService) {
}
ngOnInit() {
this.heroService.getHeroes()
.then(heroes => this.heroes = heroes);
}
gotoDetail(hero: Hero) {
let link = ['/detail', hero._id];
this.router.navigate(link);
}
}
Everything from the example tutorial expects the id of the returned data to be numeric. And If I change the number value to be string instead in..
//hero.ts
export class Hero {
_id: number;
name: string;
}
and all other places where this occur I get a bunch of errors, I can't show every place, this would result in to much example code.
My REST API in node:
(That works as expected when using postman)
//server/routes/admin.js
var express = require('express');
var app = express();
var router = express.Router();
var passport = require('passport');
var User = require('../models/user');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');
var session = require('express-session');
router.get('/users', /*isAdmin,*/ function(req, res) {
User.find(function(err, users){
if (err)
return res.send(err);
res.json(users);
});
});
//CRUD operations for a single Company by its id
router.route('/users/:id')
.get(/*isAdmin, */function(req, res){
User.findById(req.params.id, function(err, user){
if (err)
res.send(err);
res.json(user);
});
})
How would I do to find one single document from mongoDb with respect to its _id with angular from the client? Anything that could point me in the right direction.
I suppose there is a specific HTTP route for retrieving a single hero/document. Here is how it should be done in the client :
getHero(_id: number) {
return this.http.get(this.heroesUrl + '/' + _id)
.toPromise()
.then(response => response.json() as Hero)
.catch(this.handleError);
}
I suppose you should have a route :
router.get('/users/:id', /*isAdmin, */function(req, res){
User.findById(req.params.id, function(err, user){
if (err)
res.send(err);
res.json(user);
});
})