# Fields
The entrypoints to any GraphQL API are the fields of the root types Query
, Mutation
and Subscription
.
Every field has a function associated with it that is called when the field is requested as part of a query. This function is called a resolver.
# Hello World
As is the tradition of our people, this section will teach you how to say "hello world!" through Lighthouse.
We start out by defining the simplest possible schema: The root Query
type
with a single field called hello
that returns a String
.
type Query {
hello: String!
}
This defines the shape of our data and informs the client what they can expect. You need to implement the actual resolver next.
By default, Lighthouse looks for a class with the capitalized name of the field in App\GraphQL\Queries
or App\GraphQL\Mutations
and calls its __invoke
function with the usual resolver arguments.
In this case, our field is a query and is called hello
, so we need to define our class as follows:
namespace App\GraphQL\Queries;
class Hello
{
public function __invoke(): string
{
return 'world!';
}
}
The easiest way to create such a class is to use the built in artisan
commands
lighthouse:query
and lighthouse:mutation
. They both take a single argument:
the name of the field you want to generate.
For example, this is how you generate a class for the field hello
:
php artisan lighthouse:query Hello
Now your schema can be queried.
{
hello
}
This query will return the following response:
{
"data": {
"hello": "world!"
}
}
# Fields with arguments
As we learned, every field has a resolver function associated with it. Just like functions, fields can take arguments to control their behaviour.
Let's construct a query that greets the user. We add a required argument name
that is used to construct the greeting.
type Query {
greet(name: String!): String
}
A minimal implementation of the field could look something like this.
The skeleton for this class can be created using php artisan lighthouse:query Greet
.
The second argument of the resolver function is an associative array of the arguments that are passed to the query.
namespace App\GraphQL\Queries;
class Greet
{
public function __invoke($rootValue, array $args): string
{
return "Hello, {$args['name']}!";
}
}
We can call this query, passing a name
of our choosing.
{
greet(name: "Foo")
}
And receive a friendly greeting.
{
"data": {
"greet": "Hello, Foo!"
}
}
If we don't want to require the user to pass an argument, we can modify our schema
and make the name
optional and provide a default value.
type Query {
greet(name: String = "you"): String
}
Now we can use our query like this:
{
greet
}
{
"data": {
"greet": "Hello, you!"
}
}
# Resolving non-root fields
As mentioned, every field in the schema has a resolver - but what about fields that are not on one of the root types?
type Query {
user: User!
}
type User {
id: ID!
name: String!
email: String
}
Let's play through what happens when the client sends the following query:
{
user {
id
name
}
}
First, the resolver for user
will be called. Let's suppose it returns an instance
of App\Model\User
.
Next, the field sub-selection will be resolved - the two requested fields are id
and name
.
Since we already resolved the User in the parent field, we do not want to fetch it again
to get its attributes.
Conveniently, the first argument of each resolver is the return value of the parent field, in this case a User model.
A naive implementation of a resolver for id
might look like this:
use App\Models\User;
function resolveUserId(User $user): string
{
return $user->id;
}
Writing out each such resolver would be pretty repetitive.
We can utilize the fourth and final resolver argument ResolveInfo
, which will give us access
to the requested field name, to dynamically access the matching property.
use App\Models\User;
use GraphQL\Type\Definition\ResolveInfo;
use Nuwave\Lighthouse\Support\Contracts\GraphQLContext;
function resolveUserAttribute(User $user, array $args, GraphQLContext $context, ResolveInfo $resolveInfo)
{
return $user->{$resolveInfo->fieldName};
}
Fortunately, the underlying GraphQL implementation already provides a sensible default resolver (opens new window),
that plays quite nicely with the data you would typically return from
a root resolver, e.g. Eloquent
models or associative arrays.
This means that in most cases, you will only have to provide resolvers for the root fields and make sure they return data in the proper shape.
If you need to implement custom resolvers for fields that are not on one of the
root types Query
or Mutation
, you can use either the
@field or @method directive.
You may also change the default resolver if you need.
← Types Directives →