A resolver is a place to put GraphQL operations (query
, mutation
, subscription
).
Usually we put operations that are close to each other in the same resolver, for example user related operations in a resolver called UserResolver
.
First, let's take a brief look at the basic operations of GraphQL and when you should use them:
A query is an operation that is used to get data, such as getting user information, getting a list of products, and so on. Queries usually do not change the persistent data of the service.
Mutation is an operation used to modify data, such as creating a user, updating user information, deleting a user, and so on. Mutation operations usually change the persistent data of a service.
Subscription is an operation in which the server actively pushes data to the client. Subscription usually does not change the persistent data of the service. In other words, subscription is a real-time query.
We use the resolver
function to define the resolver:
In the code above, we have defined a resolver called HelloResolver
, which has no operations for now.
Let's try to define the operation using the query
function:
In the code above, we have defined a query
operation called hello
which returns a non-null string.
Here, we're using the type definition provided by graphql.js
directly, which as you can see can be slightly verbose, and we could have chosen to simplify the code by using the schema library:
We can define the return type of the hello
operation using [valibot](. /schema-integration/valibot) to define the return type of the hello
operation:
In the code above, we use v.string()
to define the return type of the hello
operation. We can directly use the valibot
schema as the silk
.
The query
, mutation
, and subscription
operations can all accept input parameters.
Let's add an input parameter name
to the hello
operation:
In the code above, we passed in the input
property in the second argument of the query
function to define the input parameter: the input
property is an object whose key is the name of the input parameter, and whose value is the type definition of the input parameter.
Here, we use v.nullish(v.string(), “World”)
to define the name
parameter, which is an optional string with a default value of “World”
.
In the resolve
function, we can get the value of the input parameter by the first parameter, and TypeScript will derive its type for us, in this case, we directly deconstruct to get the value of the name
parameter.
We can also add more information to the action, such as description
, deprecationReason
and extensions
:
In GraphQL, we can define resolvers for fields on an object to add additional properties to the object and create relationships between objects. This allows GraphQL to build very flexible APIs while maintaining simplicity.
When using GQLoom
, we can use the resolver.of
function to define object resolvers.
We start by defining two simple objects User
and Book
:
In the above code, we have defined two objects User
and Book
which represent user and book.
In Book
, we define an authorID
field, which represents the author ID of the book.
In addition, we define two simple Map objects to store some predefined data:
Next, we define a BookResolver
:
In the above code, we have used the resolver.of
function to define BookResolver
, which is an object resolver for resolving Book
objects.
In BookResolver
, we define a books
field, which is a query operation to get all the books.
Next, we will add an additional field called author
to the Book
object to get the author of the book:
In the above code, we used the field
function to define the author
field.
The field
function takes two parameters:
Book
instance from the first parameter of the parsing function, and then we get the corresponding User
instance from the userMap
based on the authorID
field.In GraphQL, we can define input parameters for fields in order to pass additional data at query time.
In GQLoom
, we can use the second argument of the field
function to define the input parameters of a field.
In the above code, we used the field
function to define the signature
field.
The second argument to the field
function is an object which contains two fields:
input
: the input parameter of the field, which is an object containing a name
field, which is of type string
;resolve
: the field's resolver function, which takes two arguments: the first argument is the source object of the resolver constructed by resolver.of
, which is an instance of Book
; the second argument is the field's input parameter, which is an object that contains an input of the name
field.The BookResolver
object we just defined can be woven into a GraphQL schema using the weave function:
The resulting GraphQL schema is as follows: