View Source GraphQL Query Generation
Following where we left off from Getting Started with GraphQL, this guide explores what the GraphQL requests and responses look like for different queries defined with the AshGraphql DSL.
All of the following examples apply to queries & mutations places on the domain as well.
Fetch Data by ID
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 domain module:defmodule Helpdesk.Support do use Ash.Domain, extensions: [AshGraphql.Domain] 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:".