Context
I have a GraphQL API and a NodeJS & Angular application with a MongoDB database that holds users. For each user, there is a public page with
I think what you are missing here is that in GraphQL you usually want to create this deeply connected graph structure. While getUserById
and getMe
work well as entry points (and I think they are still a great idea even with the interface type), you will most likely have user types coming up all over you schema. Imagine the popular blog post example:
type Post {
id: ID!
title: String!
content: String!
author: User!
}
Adding two author fields here does not really work very well. Similarly in your example you might not know that the profile page is your own until you get a response from the backend (think about twitter profiles).
Instead, in my opinion there are two methods to consider:
First one is the interface idea. You would have an interface that has all the common fields and concrete implementations for the private and public type. The nice thing here: If you only use the common fields you don't even have to use the type matching:
query getUser($id: ID!) {
getUser(id: $id) {
id
username
# if you need a private field you can branch off here
... on UserPrivate {
email
}
}
}
When it gets more finely grained (people share what they want to expose to the public, imagine Facebook) or you have a lot of types (UserMe, UserFriend, UserStranger) you might want to consider nullable fields instead. If you don't have access to the field you will receive null from the API. To reduce the amount of null checking you can easily bundle fields into their own types (e.g. Address
).
Summary:
From the API point it is a bit easier to return nullable fields because it gives you a lot of flexibility. It is much easier to evolve the second option without breaking changes than the first one. Using interfaces is more expressive and surely more fun to work with in the frontend if you work with static types (Typescript, Flow, Scala.js, Reason, etc.). Keyword: Pattern matching.