You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
(Note: I use the phrase "resolve an entire type by ID" very liberally here... I hope that's not misleading)
Hello community! I am not entirely certain where to write this question, as it is something I have been wondering for a long time working with multiple "GraphQL on the backend" libraries, but I figured this is one where people might know the answer.
One thing that I find to be really missing in the GraphQL puzzle piece, and where googling takes me nowhere, is the ability to "resolve/hydrate a type based on its ID", similar to like a GET /my-thing/{id}, but as a top level query but rather simply as a way of organising the data fetcher code. I find the lack of this to be super confusing, as it very often creates a rift between what regular database models or similar look like and how your API behaves.
Let me give you an example. Let's say we have the following schema:
You could imagine the database model for this very simple blog had 3 basic tables:
blogpost with columns id, text, author_user_id
comment with columns id, text, blogpost_parent_id, author_user_id
user with columns id, username, display_name
Okay - Now let me get to where I struggle with designing something like this (obvious much larger and more complex in practice). Let me use GraphQL for spring to keep the example shorter.
@Controller
classBlogController(valdatabase:Database) {
@QueryMapping // Query.blogpostsfunblogposts(): List<Blogpost> {
val dbBlogposts = database.allBlogposts()
return dbBlogposts.map { blogpost ->Blogpost( // everything except author omitted// Here I have many choices.// I can choose to fetch the user directly from the DB and write it
author =User(database.getUser(blogpost.authorUserId)),
// or I can resolve only the parts of User that I know of in the Blogpost// this will require me to provide resolvers for both username and displayName elsewhere
author =User(id = blogpost.authorUserId),
// or I can resolve the entire Blogpost.author field elsewhere
author =null
)
}
}
@SchemaMapping("Blogpost") // Blogpost.commentsfuncomments(blogpost:Blogpost): List<Comment> {
val dbComments = database.allCommentsForBlogpost(blogpost.id)
return dbBlogposts.map { blogpost ->Comment(
// Here I am faced with the exact same choices when resolving `author`// Do it inline it entirely, only send ID and resolve all of its properties individually, // or omit it and resolve the entire author field separately
)
}
}
}
So... I hope this was enough to set the stage. What I feel I would want to do in this example is the following:
Return my Blogpost and Comment objects only with some type User(id = ...)
Have a single "reference resolver" or something where we can "hydrate" the entire User type and all of its fields at once.
Currently, the closest I can get right now is this:
@Controller
classUserController(valdatabase:Database) {
// What I am forced to do
@SchemaMapping("User") // User.usernamefunusername(user:User): String {
return database.getUser(user.id).username
}
@SchemaMapping("User") // User.displayNamefundisplayName(user:User): String {
return database.getUser(user.id).displayName
}
// Something I would hypothetically want to do.// Being able to do this would mean being able to simply return a "stub" or a "shell" of a User object elsewhere, and have// it populated all at once here, without needing to have resolvers for every single field performing the same DB lookup//// This would scale super well with any other new type that wanted to return a User as one of its properties, as they always// just had to return an `id` and let this handle the rest
@TypeMapping("User") // doesn't exist, but if it did it would do an initial "fetch most of user all at once" thingyfunresolverUser(partialUser:User): User {
val user = database.getUser(partialUser.id)
returnUser(user.id, user.username, user.displayName)
}
}
I know something inside Apollo Federation (entity resolvers) kinda-sorta looks like this - however it only operates "across subgraphs" (usually services), not within a single subgraph. And it's federation-specific, not native to GraphQL.
So, I hope you see what I am trying to ask about, and that people who maintain an actual server-side implementation of GraphQL might know something about it.
Is my thinking simply incompatible with how GraphQL works? Is there any way to think a bit differently about this that doesn't mean you have to write what at least feels like so much redundant and repetitive code?
PS. forgive me if this was already asked before or if this is the wrong place. I have tried any combination of keywords I can think of to find some topic in a forum or doc page related to this, but I have come up short.
reacted with thumbs up emoji reacted with thumbs down emoji reacted with laugh emoji reacted with hooray emoji reacted with confused emoji reacted with heart emoji reacted with rocket emoji reacted with eyes emoji
-
(Note: I use the phrase "resolve an entire type by ID" very liberally here... I hope that's not misleading)
Hello community! I am not entirely certain where to write this question, as it is something I have been wondering for a long time working with multiple "GraphQL on the backend" libraries, but I figured this is one where people might know the answer.
One thing that I find to be really missing in the GraphQL puzzle piece, and where googling takes me nowhere, is the ability to "resolve/hydrate a type based on its ID", similar to like a
GET /my-thing/{id}
, but as a top level query but rather simply as a way of organising the data fetcher code. I find the lack of this to be super confusing, as it very often creates a rift between what regular database models or similar look like and how your API behaves.Let me give you an example. Let's say we have the following schema:
You could imagine the database model for this very simple blog had 3 basic tables:
blogpost
with columnsid
,text
,author_user_id
comment
with columnsid
,text
,blogpost_parent_id
,author_user_id
user
with columnsid
,username
,display_name
Okay - Now let me get to where I struggle with designing something like this (obvious much larger and more complex in practice). Let me use GraphQL for spring to keep the example shorter.
So... I hope this was enough to set the stage. What I feel I would want to do in this example is the following:
Blogpost
andComment
objects only with some typeUser(id = ...)
User
type and all of its fields at once.I know something inside Apollo Federation (entity resolvers) kinda-sorta looks like this - however it only operates "across subgraphs" (usually services), not within a single subgraph. And it's federation-specific, not native to GraphQL.
So, I hope you see what I am trying to ask about, and that people who maintain an actual server-side implementation of GraphQL might know something about it.
Is my thinking simply incompatible with how GraphQL works? Is there any way to think a bit differently about this that doesn't mean you have to write what at least feels like so much redundant and repetitive code?
PS. forgive me if this was already asked before or if this is the wrong place. I have tried any combination of keywords I can think of to find some topic in a forum or doc page related to this, but I have come up short.
Beta Was this translation helpful? Give feedback.
All reactions