I'm trying to wrap my head around Prisma and GraphQL, using GraphQL-Yoga. One thing that has me puzzled in the resolvers. In the Prisma examples (https://github.com/prisma/prisma-examples/blob/master/node/graphql/src/index.js) the DB calls seem to be synchronous, e.g.
Mutation: {
signupUser: (parent, { email, name }, context) => {
return context.prisma.createUser({
email,
name,
})
},
but I've seen other examples where one must await
the return from Prisma. Shouldn't all these DB access calls be asynchronous, like
Mutation: {
signupUser: async (parent, { email, name }, context) => {
return await context.prisma.createUser({
email,
name,
})
},
First, resolvers (can) return a promise. They don't have to but in both of your code examples the resolvers return a promise. Get comfortable with promises, almost all asyncronous things are done with promises these days!
Next you should read about async functions in JavaScript. async/await is syntactic sugar for promises. As such they always return a promise (even if you don't use await
inside).
The first example returns a Promise explicitly. The second example does the same but implicitly (also the await is not needed here but this would make it explicit again). Both examples get more interesting, when you actually modify the value afterwards:
signupUser: (parent, { email, name }, context) => {
return context.prisma.createUser({
email,
name,
}).then(user => {
return { ...user, isCool: user.friends > 5 };
});
}
// vs. async function
signupUser: async (parent, { email, name }, context) => {
const user = await context.prisma.createUser({
email,
name,
};
return { ...user, isCool: user.friends > 5 };
}
Syntactic sugar mean that there is no actual new language feature behind it. Often compilers first desugar a syntax before compiling it (esp. in functional languages). As a mental model you can imagine async functions to be rewritten to promise form. This will make it easier to understand why they always return a promise and what they are actually doing.
After grasping this concept you will understand that both examples are in fact asyncronous and that the await
in your example is optional (but only because it follows the return. If you look at the second example you might also see why people claim that "async looks more syncronous": It gets rid of the callbacks.