GraphQL Query Generation
Table of Contents
Fetch Data by ID
Following where we left off from Getting Started with GraphQL , we’ll explore what the GraphQL requests and responses look like for different queries defined with the AshGraphql DSL.
defmodule Helpdesk.Support.Ticket do
use Ash.Resource,
...,
extensions: [
AshGraphql.Resource
]
attributes do
# Add an autogenerated UUID primary key called `:id`.
uuid_primary_key :id
# Add a string type attribute called `:subject`
attribute :subject, :string
end
actions do
# Add a set of simple actions. You'll customize these later.
defaults [:read, :update, :destroy]
end
graphql do
type :ticket
queries do
# create a field called `get_ticket` that uses the `read` read action to fetch a single ticket
get :get_ticket, :read
end
end
end
For the
get_ticket
query defined above, the corresponding GraphQL would look like this:
query($id: ID!) {
getTicket(id: $id) {
id
subject
}
}
And the response would look similar to this:
{
"data": {
"getTicket": {
"id": "",
"subject": ""
}
}
}
Let’s look at an example of querying a list of things.
graphql do
type :ticket
queries do
# create a field called `get_ticket` that uses the `read` read action to fetch a single ticket
get :get_ticket, :read
# create a field called `list_tickets` that uses the `read` read action to fetch a list of tickets
list :list_tickets, :read
end
end
This time, we’ve added
list :list_tickets, :read
, to generate a GraphQL query for listing tickets.
The request would look something like this:
query {
listTickets {
id
subject
}
}
And the response would look similar to this:
{
"data": {
"listTickets": [
{
"id": "",
"subject": ""
}
]
}
}
Filter Data With Arguments
Now, let’s say we want to add query parameters to
listTickets
. How do we do that?
Consider
list :list_tickets, :read
and the
actions
section:
actions do
# Add a set of simple actions. You'll customize these later.
defaults [:read, :update, :destroy]
end
graphql do
type :ticket
queries do
# create a field called `list_tickets` that uses the `read` read action to fetch a list of tickets
list :list_tickets, :read
end
end
The second argument to
list :list_tickets, :read
is the action that will be called when the query is run.
In the current example, the action is
:read
, which is the generic Read action.
Let’s create a custom action in order to define query parameters for the
listTickets
query.
We’ll call this action
:query_tickets
:
actions do
defaults [:read, :update, :destroy]
read :query_tickets do
argument :representative_id, :uuid
filter(
expr do
is_nil(^arg(:representative_id)) or representative_id == ^arg(:representative_id)
end
)
end
end
graphql do
type :ticket
queries do
# create a field called `list_tickets` that uses the `:query_tickets` read action to fetch a list of tickets
list :list_tickets, :query_tickets
end
end
In the
graphql
section, the
list/2
call has been changed, replacing the
:read
action with
:query_tickets
.
The GraphQL request would look something like this:
query($representative_id: ID) {
list_tickets(representative_id: $representative_id) {
id
representative_id
subject
}
}
Mutations and Enums
Now, let’s look at how to create a ticket by using a GraphQL mutation.
Let’s say you have a Resource that defines an enum-like attribute:
defmodule Helpdesk.Support.Ticket do
use Ash.Resource,
...,
extensions: [
AshGraphql.Resource
]
attributes do
uuid_primary_key :id
attribute :subject, :string
attribute :status, :atom, constraints: [one_of: [:open, :closed]]
end
actions do
defaults [:create, :read, :update, :destroy]
end
graphql do
type :ticket
queries do
get :get_ticket, :read
end
mutations do
create :create_ticket, :create
end
end
end
Above, the following changes have been added:
-
In the
attributes
section, the:status
attribute has been added. -
In the
actions
section, the:create
action has been added. -
The
:create_ticket
mutation has been defined in the newgraphql.mutations
section.
The
:status
attribute is an enum that is constrained to the values
[:open, :closed]
.
When used in conjunction with AshGraphql, a GraphQL enum type called
TicketStatus
will be generated for this attribute.
The possible GraphQL values for
TicketStatus
are
OPEN
and
CLOSED
.
See
Use Enums with GraphQL
for more information.
We can now create a ticket with the
createTicket
mutation:
mutation($input: CreateTicketInput!) {
createTicket(input: $input) {
result {
id
subject
status
}
errors {
code
fields
message
shortMessage
vars
}
}
}
Note
-
The resulting ticket data is wrapped in AshGraphql’s
result
object. -
Validation errors are wrapped in a list of error objects under
errors
, also specified in the query. AshGraphql does this by default instead of exposing errors in GraphQL’s standarderrors
array. This behavior can be changed by settingroot_level_errors? true
in thegraphql
section of your Ash API module:defmodule Helpdesk.Support do use Ash.Api, extensions: [AshGraphql.Api] graphql do root_level_errors? true end end
If we were to run this mutation in a test, it would look something like this:
input = %{
subject: "My Ticket",
status: "OPEN"
}
resp_body =
post(conn, "/api/graphql", %{
query: query,
variables: %{input: input}
})
|> json_response(200)
Notice that the
status
attribute is set to
"OPEN"
and not
"open"
. It is important that the value of the
status
be uppercase.
This is required by GraphQL enums. AshGraphql will automatically convert the value to the correct case.
The response will look something like this:
{
"data": {
"createTicket": {
"result": {
"id": "b771e433-0979-4d07-a280-4d12373849aa",
"subject": "My Ticket",
"status": "OPEN"
}
}
}
}
Again, AshGraphql will automatically convert the
status
value from
:open
to
"OPEN"
.
More GraphQL Docs
If you haven’t already, please turn on the documentation tag for AshGraphql. Tags can be controlled at the top of the left navigation menu, under “Including Libraries:”.
- Getting Started With GraphQL
-
AshGraphql.Api