Queries and mutations are the entry point to the GraphQL service.
Fields
Each type is composed of one or more fields, which can be scalar values or complex objects that refer to other types, resulting in nesting. All GraphQL queries must at least specify fields to be returned. This is referred to as the selection set.
Consider the following schema:
type Query {
topRatedMovies: [Movie]
}
type Movie {
id: ID!
title: String
year: Int
plot: String
poster: String
imdbRating: Float
genres: [String]
similar(limit: Int = 3): [Movie]
rating: RATING
actors: [Actor]
avgStars: Float
}
We can query:
Query
{
topRatedMovies {
title
year
avgStars
}
}
Result
{
"data": {
"topRatedMovies": [
{
"title": "Godfather, The",
"year": 1972,
"avgStars": 4.4875
},
{
"title": "Shawshank Redemption, The",
"year": 1994,
"avgStars": 4.487138263665597
},
{
"title": "On the Waterfront",
"year": 1954,
"avgStars": 4.448275862068966
}
]
}
}
Optionally, we can include the operation type and operation name in our query, in addition to our selection set.
query TopRatedMoviesAndRating {
topRatedMovies {
title
year
avgStars
}
}
This blog post contains a good overview of GraphQL terminology, including terms like selection set, operation, and operation name.
Arguments
We can also pass arguments to our queries. Arguments can be required or optional. When using an optional argument, we declare a default value. We've seen an example of passing an argument already, but here we also pass an argument to a field on the Movie
type as well as to our root level query:
type Query {
moviesByTitle(title: String!, limit: Int = 3): [Movie]
}
Query
{
moviesByTitle(title: "Matrix Reloaded") {
title
similar(limit: 2) {
title
year
}
}
}
Result
{
"data": {
"moviesByTitle": [
{
"title": "Matrix Reloaded, The",
"similar": [
{
"title": "Matrix, The",
"year": 1999
},
{
"title": "Lord of the Rings: The Fellowship of the Ring, The",
"year": 2001
}
]
}
]
}
}
Variables
To avoid injection attacks by string interpolation to build queries from dynamic or user-supplied content, we can use variables in our GraphQL query. To use variables, we first declare $varName
as a valid variable for our query, then replace the value in the query with $varName
. Finally, we pass the key-value pair varName: value
in a dictionary alongside the query. For example:
Query
query MoviesByTitle($movieTitle: String!, $similarLimit: Int) {
moviesByTitle(title: $movieTitle) {
title
similar(limit: $similarLimit) {
title
year
}
}
}
Variables
{
"movieTitle": "Matrix Reloaded",
"similarLimit": 2
}
Result
{
"data": {
"moviesByTitle": [
{
"title": "Matrix Reloaded, The",
"similar": [
{
"title": "Matrix, The",
"year": 1999
},
{
"title": "Lord of the Rings: The Fellowship of the Ring, The",
"year": 2001
}
]
}
]
}
}
Mutations
While queries allow us to request data, GraphQL mutations are used for updating data and provide an additional entry-point into our GraphQL API. To use mutations, we include a Mutation
type in our schema, which defines the mutations allowed in our GraphQL service. One way to think of mutations is as user-defined commands where the logic is defined in the GraphQL server implementation.
Consider a UserReview
type, which is composed of a User,
a Movie,
and an integer rating of the movie:
type UserReview {
user: User
rating: Int
movie: Movie
}
To create a new UserReview
, we must define a mutation to perform this update. Our mutation will need to accept the userId
and movieId
arguments as well as the integer rating
:
type Mutation {
reviewMovie(userId: ID!, movieId: ID!, rating: Int): UserReview
}
Note that our mutation returns a UserReview
object. This means that we can access any of the fields available on Movie
and User
(in a nested fashion):
Query
mutation {
reviewMovie(userId: "20", movieId: "16", rating: 5) {
movie {
title
similar(limit: 2) {
title
}
}
user {
name
}
rating
}
}
Result
{
"data": {
"reviewMovie": {
"movie": {
"title": "Casino",
"similar": [
{
"title": "Four Brothers"
},
{
"title": "Night and the City"
}
]
},
"user": {
"name": "Nicole Ramsey"
},
"rating": 5
}
}
}
In the previous mutation example, we passed three individual arguments of primitives to define the update we wanted to make. We can instead use an input type to pass a more complex object as a variable. Input types are especially useful for mutations where we want to pass our update as a single object.
First, we define our input type:
input ReviewInput {
rating: Int!
movieId: ID!
userId: ID!
}
Then, we modify our reviewMovie
mutation to accept an argument of type ReviewInput
:
type Mutation {
reviewMovie(review: ReviewInput!): UserReview
}
Then our query becomes:
Query
mutation CreateReviewForMovie($review: ReviewInput) {
reviewMovie(review: $review) {
movie {
title
}
user {
name
}
rating
}
}
Variables
{
"review": {
"movieId":"16",
"userId":"20",
"rating": 5
}
}
Result
{
"data": {
"reviewMovie": {
"movie": {
"title": "Casino"
},
"user": {
"name": "Nicole Ramsey"
},
"rating": 5
}
}
}
Fragments
A fragment is a reusable set of fields that we can define and reference by name in a GraphQL query. Fragments allow us to avoid repetition in our queries by giving us a way to reference this set of fields by name. To apply a fragment inside a query, we use a fragment spread operator inside our selection set:
Query
{
moviesByTitle(title: "Matrix Reloaded") {
...movieSummaryFields
}
}
fragment movieSummaryFields on Movie {
title
year
imdbRating
}
Result
{
"data": {
"moviesByTitle": [
{
"title": "Matrix Reloaded, The",
"year": 2003,
"imdbRating": 7.2
}
]
}
}
Inline Fragments
Let's say that we have a union type PersonResult
returned by a query called personByName
:
type Query {
personByName(name: String!): [PersonResult]
}
union PersonResult = User | Actor
PersonResult
can be either a User
or Actor
. In this case, we'll need to use an inline fragment to ensure the result of our query is resolved to the correct type.
Query
{
personByName(name: "Tom Cruise", limit:3) {
... on Actor {
name
movies {
title
}
}
... on User {
name
}
}
}
Result
{
"data": {
"personByName": [
{
"name": "Tom Cruise",
"movies": [
{
"title": "Risky Business"
},
{
"title": "Cocktail"
},
{
"title": "Top Gun"
}
]
}
}
}
{{ parent.title || parent.header.title}}
{{ parent.tldr }}
{{ parent.linkDescription }}
{{ parent.urlSource.name }}