Return list from Graphql resolve - react-native

fetchFriends: {
type: new GraphQLList(UserType),
args: {
currentId: { type: new GraphQLNonNull(GraphQLID) }
},
resolve: (_, {currentId}) => {
return Promise.resolve()
.then(() => {
User.findById(currentId, (err, users) => {
users.getFriends((err, user) => {
console.log(user);
return user;
});
});
})
}
/* another version what i tried that returns only the initial findById user
resolve: (_, {currentId}) => {
var value = User.findById(currentId, (err, user) => {
new Promise((resolve, reject) => {
user.getFriends((err, user) => {
console.log('fetch: ', user);
err ? reject(err) : resolve(user)
});
})
})
return value;
}*/
},
I have a graphql resolve that i am getting the User object within the findById callback. that specific object calls getFriends which is a part of a mongoose plugin (friends-of-friends) and the console.log within getFriends callback contains the list in the terminal so i know getFriends
is returning the proper data but i cannot figure out how to return the value into my React-Native Component. i have tried for the past 8 hours everything i can think of and cannot get the value returned out of this function.

You're close, but there's a couple of things to keep in mind when working with resolvers:
Your resolver has to return either a value that matches the type/scalar specified in your schema or a Promise that will resolve to that value.
Mongoose operations can return a promises, and you should utilize this feature of them rather than trying to wrap callbacks inside Promises as this can easily get messy
Return statements inside callbacks at least in this context) don't actually do anything. Return statements inside a then, on the other hand, determine what the promise will resolve to (or what promise to invoke next in the chain).
I would imagine your resolver needs to look something like this:
resolve (_, {currentId}) => {
// calling exec() on the query turns it into a promise
return User.findById(currentId).exec()
// the value the promise resolves to is accessible in the "then" method
.then(user => {
// should make sure user is not null here, something like:
if (!user) return Promise.reject(new Error('no user found with that id'))
// we want the value returned by another async method, getFriends, so
// wrap that call in a promise, and return the promise
return new Promise((resolve, reject) => {
user.getFriends((error, friends) => {
if (error) reject(error)
resolve(friends)
})
})
})
}

Related

React Hook does not set on first API call

So I am sure I am messing something up, but I am not super skilled at API.
So I am trying to make an API call to check if the user exists, if user exists then move about business, if not then do other stuff.
So my first call gets the data, and the user DOES exist, the hook is setting to true, however in my log it fails and the next API is ran. However if I do it a 2nd time, it is true...
What am I doing wrong.
const handleSubmit = async () => {
const data = await axios
.get(`URL`, {
})
.then((resp) => {
if (resp.data.user.name) {
setCheckUser(true);
console.log(resp.data.user.name);
}
return data;
})
.catch((err) => {
// Handle Error Here
console.error(err);
});
console.log(checkUser);
if (!checkUser) {
console.log('No User Found');
//Do Stuff//
}
};
I think the problem here is that setCheckUser(true) is an async operation, so there is no guarantee that the checkUser variable will turn to true right away.
Maybe you can solve this by using a useEffect block like this
//somewhere on the top of your file, below your useState statements
useEffect(()=> {
if (!checkUser) {
console.log('No User Found');
//Do Stuff//
}
}, [checkUser])
const handleSubmit = async () => {
const data = await axios
.get(`URL`, {
})
.then((resp) => {
if (resp.data.user.name) {
setCheckUser(true);
console.log(resp.data.user.name);
}
return data;
})
.catch((err) => {
// Handle Error Here
console.error(err);
});
};

returning sqlite3 query in Node

I'm trying to write a function that returns a query from a sqlite3 database (using Node and Express)
This is how (likely) the function is called
app.get('/example',(req,res)=>{
console.log(getThings(db_connection))
}
And this is the function per se
getThings(db){
let sql = 'SELECT * FROM Table'
let results[]
db.all(sql, (err, rows) => {
if(err){throw err}
let i
for(i=0;i<rows.length;i++){
res.push(rows[i])
}
console.log(res)
})
return res
}
I expected the rows being returned at the end, but it always returns res before populating it first, and just then it prints res with the correctly
I might have understood why it does so, but I have no idea how to fix it properly (I'm still new at JS)
Callbacks are asynchronous, so res will not be populated before the return.
You need to make your callback into a Promise or use async/await.
Promisify the callback:
getThings(db){
return new Promise((resolve, reject) => {
db.all('SELECT * FROM Table', (err, rows) => {
if (err) reject(err)
resolve(rows)
})
})
}
app.get('/example', (req, res) => {
getThings(db_connection)
.then(rows => res.send(result))
.catch(err => res.send({
error: err.message
}))
}
or
Use async/await:
Wrapped in try/catch to catch err, then because you're simply looping over the rows you don't need the for loop.
When you see the following structure object.method('param', (err, rows) => { you can almost guarantee its Promise compatible, else if not you can use util.promisify(original) to make it so.
Cleaner and more verbose then then().catch() chaining:
app.get('/example', async (req, res) => {
let result = {}
try {
result = await getThings(db_connection)
} catch (err) {
result = {
error: err.message
}
}
res.send(result)
}
async getThings(db) {
return db.all('SELECT * FROM Table')
}

Callback function 'next' is executed automatically without making a call to it

I have this POST method which uses FetchURL middleware to fetch data from the url submitted by the user.
router.post('/', FetchURL, (req, res) => {
console.info('data received');
...
})
Everything works with response.ok being true, but the contrary case doesn't quite work as expected.
I don't want next to be called when response.ok equals false.
But I get to see "data received" logged to the console which means the next function does get called on its own.
fetch_url.js
function FetchURL(req, res, next) {
fetch(req.body.input_url)
.then(response => {
if(response.ok)
return response.json();
// else render error message on the client machine
res.status(response.status)
.render('index', {
errStatus: [response.status, response.statusText]
});
/* Throwing an Error here is the only way I could prevent the next callback */
// throw new Error(`Request failed with status code ${response.status}.`);
})
.then(data => {
req.data = data;
next();
})
.catch(err => console.error(err));
}
I could not find anything relevant on the documentation of expressjs middleware. The only way I could prevent next from being called is by throwing an Error on the server.
What happens behind the scene here?
try making a second check before next is called like following
function FetchURL(req, res, next) {
fetch(req.body.input_url)
.then(response => {
if(response.ok) // wrap your response in a temporary object.
return { fail: false, data: response.json() } ;
// else render error message on the client machine
res.status(response.status)
.render('index', {
errStatus: [response.status, response.statusText]
});
/* Instead of throwing an Error, return something indicating error */
return { fail: true };
})
.then(data => {
// check if previous procedure has failed.
if(!data.fail) {
req.data = data.data;
next();
}
})
.catch(err => console.error(err));
}

Jest: ReferenceError: Request is not defined

I can't get my jest test to pass even though the code works:
describe("Testing the API call", () => {
test("Testing the API call", () => {
sendToServer("Hey there!")
})
})
And jest throws me this:
ReferenceError: Request is not defined (it can't find Request constructor)
I'm pretty new to jest so I have only tried what I could find on stack overflow, but there are no solutions to this one. I tried to import Request from html and it didn't work.
It would be easier to help you if you would share your getData function, but let me assume that you are doing something like, for fetching your data:
async function getUsers() {
const URL = `https://randomuser.me/api/?results=10`;
try {
const response = await fetch(URL);
return response.json();
}
catch (e) {
console.log(e);
return {}
}
}
The above function will make a call to the Random User API and return an Object with an array of results, in our case 10 random users.
In order to test this function, you can write tests, such as:
describe('getUsers function', () => {
test('the data returned is an object', async () => {
const data = await index.getUsers();
expect(data).toBeInstanceOf(Object);
});
test('the Results array has 10 entries', async () => {
const data = await index.getUsers();
expect(data.results.length).toBe(10)
});
});
Here you will assert, that you do return Object from the call and that you do return correct number of users on call.

PUT request only occurs on second attempt

I have an express route that changes a Post's "checked" value to it's opposite boolean value (true => false, false => true). For some reason, the API return the opposite of what is in the DB. If I do a GET request after a PUT request, I get the opposite boolean value of what the PUT route gives me, which is accurate to the state of the DB.
Here is the route. Anyone see what's going on here?
app.put('/posts/:id', jsonParser, (req, res) => {
let id = req.params.id;
Post.findById( id )
.then(post => {
if(!post) {
return res.status(404).json({ message: 'Post not found' });
}
return Post.findByIdAndUpdate(id, { "checked": !post.checked })
})
.then(result => {
return res.status(202).json(result.apiRepr())
})
.catch(err => {
if(err) {
return res.status(500).json({ message: "There was a problem"})
}
});
});
It appears the .findByIdAndUpdate part IS updating the DB, but then the object below that gets returned is still the old data.
By default findByIdAndUpdate return the original document, you have to set the new option to true in order to get the modified document rather than the original:
return Post.findByIdAndUpdate(id, { "checked": !post.checked }, { new: true }) ...
findByIdAndUpdate Api doc