I was thinking of writing an API that does the following things:
{ name: “Quotes”, attributes: [“quote”, “author"] }
){ quote: "...", author: "..." }
)I would build the queries somewhat like this:
// return the name and id of all the user's maps
maps(authToken="…") {
name,
id
}
// return all the items of a single map
maps(authToken="…") {
map(name=“Quotes") {
items
}
}
// OR by using the map_id
maps(authToken="…") {
map(id=“…") {
items
}
}
So, my question is, is this correct or would I need to structure it differently?
I'd recommend constructing authentication outside of GraphQL itself, and letting your schema logic handle authorization. For example, if you are using the express-graphql
NPM module, you can check your cookies or HTTP Basic Auth or whatever mechanism you want to use to get your auth token, and then pass your authenticated viewer object down through the schema via the rootValue
, which is available at every level during query resolution:
app.use('/graphql', (request, response, next) => {
const viewer = getViewerFromRequest(); // You provide this.
const options = {
rootValue: {
viewer,
},
schema,
};
return graphqlHTTP(request => options)(request, response, next);
});
And then inside the schema you have access to your rootValue and can use that for the purposes of access control and authorization:
resolve: (parent, args, {rootValue}) => {
const viewer = {rootValue};
// Code that uses viewer here...
}
Note that as of graphql v0.5.0, the resolve
signature has changed and a third, "context" parameter has been inserted at position 3 in the argument list. This parameter is suitable for passing down an auth token or similar:
resolve: (parent, args, authToken, {rootValue}) => {
// Code that uses the auth token here...
}
I offered an approach that structures resolvers as a composition of smaller functions to help in solving this exact problem. You can see the full answer here: How to check permissions and other conditions in GraphQL query?.
The basic concept is that if you structure your resolvers as small functions that are composed together you can layer different authorization/authenication mechanisms on top of one another and throw an error in the first one that is not satisfied. This will help keep your code clean, testable, and re-usable as well :)
Also yes, the resolver context is a great place to store authentication information as well as other goodies that might need to be used throughout your resolvers.
Happy Hacking!
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With