Type resolution in Graphql
In GraphQL there are several places where permission is required Type
, not only field
in Type
.
API Backend -
-
/users
- list of users - minimum information - name, id -
/users/:id
- detailed information about the user -
/foo
- returns the owner of the field, which is the UserID
Request and schema
Create a schema to run the next query
query a {
users {
age # some detail info
}
foo {
owner {
location # some detail info
}
}
}
and the circuit could be as follows:
type Query {
users: [User]
foo: Foo
}
type Foo {
owner: User
}
type User {
id: ID
age: Int
location: String
}
Problem
The resolvers in the above diagram have to contain / process custom detail information, getting called in two different places. 1. List of users - Query.users
and 2 Query.foo.owner
.. And the thing to remember is to handle this type where you only have a user id to convert it to an actual user.
Possible Solution
Starting with this post, GraphQL supports resolveType
on Interface
and Union
. It is not possible to specify a resolver for an integer Type
- only a field
in Type
can have a resolver. So if it is possible to resolve the type in GraphQL it will simplify the implementation.
Alternative solution
Since only fields in a type are allowed, it is possible to create an additional Type
and support handling of that field in a type in converters and is in one place. But now the query is deeper than before, one level.
query b {
users {
details {
age
}
}
foo {
owner {
details {
location
}
}
}
}
Other similar scenarios
Since a Type
cannot be resolved in GraphQL enums
faces the same problem. When you have a special character in an API response and the field is an ENUM, you either don't know how to handle it in all the places where this enum is used, or you create an additional type to represent that enumeration.
I created minimal reproduction for all of these cases with ApolloGraphQL - https://github.com/boopathi/graphql-test-1
Questions
- Shouldn't one support schema / language in defining how to handle a specific type / recognizer pointer for a type instead of just a field in the type? If not, why not?
- How do you deal with these things in your circuit. Is there any other way to do this?
source to share
You're right - this is definitely something about GraphQL, which is a little weird. Basically, due to how converters work, it is the type you came from, not the type you intend to work with, that is responsible for choosing the correct data.
There are pros and cons to this approach. You can definitely imagine a GraphQL implementation where the parent simply returns an id and then you have one recognizer for each type that knows how to get the data. I think it would definitely be better for some cases.
Here's how we now propose to structure the code to avoid this kind of relationship:
- Define model classes or repository objects for the different source data sources and object types you have.
- Use the ones in your permissions instead of directly accessing the database.
To get addicts injected from poor people, we put them on context
servers. When you add it all up, it looks like this:
Scheme:
# Information about a GitHub repository submitted to GitHunt
type Entry {
# Information about the repository from GitHub
repository: Repository!
# The GitHub user who submitted this entry
postedBy: User!
...
resolvers:
export const resolvers = {
Entry: {
repository({ repository_name }, _, context) {
return context.Repositories.getByFullName(repository_name);
},
postedBy({ posted_by }, _, context) {
return context.Users.getByLogin(posted_by);
},
...
This can be seen in the context of the entire server in the GitHunt-API sample application.
Basically this approach uses resolvers as a thin wrapper that invokes basic business logic, much like a router. This is consistent with current literature on servers on Facebook and otherwise .
source to share