Schemas, types, and resolvers; what are they and how do they fit together?
Let's start with schemas - it's where we define the shape of our data - we do this by giving it a type.
When we create a schema, we do so in a different language. Don't panic, it's simple. It's called schema definition language and its very similar to defining an object.
type Post {
id: ID!
title: String!
author: String!
body: String!
}
This Post type has four fields with key names (id, title, author, body) and scalar types that describe the information stored there.
Scalar types
Scalar types are built-in types provided by GraphQL, and you’ll probably recognise most of them - they are String
, Int
, Float
, Boolean
, ID
.
We can define relationships between types too; for example, if we wanted to store more information about an author, but separately to the Post, we could do this:
type Post {
id: ID!
title: String!
author: Author!
body: String!
},
type Author {
id: ID!
name: String!
}
The type associated with the author
field is now the Author
type, which is made up of fields which have their own scalar types.
We also define any queries or mutations we make in the schema too. When we define the type a query or mutation will have, we have to make sure that whatever the associated resolver returns has the same type.
type Query {
allPosts : [Post!]!
}
And resolvers?
Resolvers are functions that resolve a value for a type or field in a schema, and they do a similar job as controllers do in REST.
We have defined the return type of our queries in the schema, the resolver now takes the data that we get from the query and transforms it into a shape that matches the one that was described by the type in the schema.
That might be a lot to think about, so picture it this way:
There's a query type in the schema that says it returns a triangle. When we get the data, we see that it actually gives us a square, so we write a resolver function to transform that square into a triangle.
Resolver functions can return objects or scalars. If an object is returned, execution continues to the next child (like from Post
to Author
in the example above), until a scalar value is returned at which point the execution is completed. If null is returned, the execution stops.
The resolvers for query and mutation types have to have the same name as the query or mutation type that they are resolving, that's how GraphQL knows which resolver to invoke.
Resolvers are like normal functions, so you can pass arguments to them too. Its often convenient to destructure these parameters.
And there you have it, a brief introduction to schemas, types, and resolvers.
Top comments (0)