ash_graphql/documentation/tutorials/getting-started-with-graphql.md

170 lines
4.6 KiB
Markdown
Raw Normal View History

# Getting Started With GraphQL
2020-08-14 10:55:34 +12:00
## Get familiar with Ash resources
improvement!: port AshGraphql to Ash 3.0 (#123) Step 1: update Ash Step 2: mass rename Api to Domain Step 3: Ash.Query.expr -> Ash.Expr.expr Also change ref interpolation Step 4: remove all warnings Step 5: remove registries from tests Step 6: fix filter Step 7: private? -> !public? Step 8: Ash.Calculation -> Ash.Resource.Calculation Step 9: use depend_on_resources/1 -> resources/1 Step 10: add Domain to all resources Step 11: use Ash module for all actions Step 12: add public? true all around Step 13: remove verbose? from options passed during Domain calls Step 14: add simple_sat Step 15: Ash.ErrorKind is no more, so remove code from errors Step 16: sprinkle default_accept :* around tests Step 17: replace Ash.Changeset.new/2 with Ash.Changeset.for_* Step 18: calculation fixups - Context is now a struct and arguments go under the arguments key - Function based calculations receive a list of records - Add a select to query-based loads - select -> load Step 19: pass the correct name to pass the policy in tests Step 20: Ash.Query.new/2 is no more Step 21: add AshGraphql.Resource.embedded? utility function Use that instead of Ash.Type.embedded_type?(resource_or_type) since resources are not types anymore Step 22: handle struct + instance_of: Resource in unions Resources are not type anymore so they need to be passed this way in unions Step 23: ensure we only check GraphQL actions for pagination All reads are now paginated by default, so this triggered a compilation error Step 24: swap arguments for sort on calculations Step 25: remove unused debug? option
2024-04-02 07:03:06 +13:00
If you haven't already, read the [Ash Getting Started Guide](https://hexdocs.pm/ash/get-started.html). This assumes that you already have resources set up, and only gives you the steps to _add_ AshGraphql to your resources/domains.
2020-08-14 10:55:34 +12:00
## Bring in the ash_graphql dependency
```elixir
def deps()
[
...
2024-04-28 01:28:46 +12:00
{:ash_graphql, "~> 1.0.0-rc.5"}
]
end
```
improvement!: port AshGraphql to Ash 3.0 (#123) Step 1: update Ash Step 2: mass rename Api to Domain Step 3: Ash.Query.expr -> Ash.Expr.expr Also change ref interpolation Step 4: remove all warnings Step 5: remove registries from tests Step 6: fix filter Step 7: private? -> !public? Step 8: Ash.Calculation -> Ash.Resource.Calculation Step 9: use depend_on_resources/1 -> resources/1 Step 10: add Domain to all resources Step 11: use Ash module for all actions Step 12: add public? true all around Step 13: remove verbose? from options passed during Domain calls Step 14: add simple_sat Step 15: Ash.ErrorKind is no more, so remove code from errors Step 16: sprinkle default_accept :* around tests Step 17: replace Ash.Changeset.new/2 with Ash.Changeset.for_* Step 18: calculation fixups - Context is now a struct and arguments go under the arguments key - Function based calculations receive a list of records - Add a select to query-based loads - select -> load Step 19: pass the correct name to pass the policy in tests Step 20: Ash.Query.new/2 is no more Step 21: add AshGraphql.Resource.embedded? utility function Use that instead of Ash.Type.embedded_type?(resource_or_type) since resources are not types anymore Step 22: handle struct + instance_of: Resource in unions Resources are not type anymore so they need to be passed this way in unions Step 23: ensure we only check GraphQL actions for pagination All reads are now paginated by default, so this triggered a compilation error Step 24: swap arguments for sort on calculations Step 25: remove unused debug? option
2024-04-02 07:03:06 +13:00
## Add the domain Extension
2020-08-14 10:55:34 +12:00
improvement!: port AshGraphql to Ash 3.0 (#123) Step 1: update Ash Step 2: mass rename Api to Domain Step 3: Ash.Query.expr -> Ash.Expr.expr Also change ref interpolation Step 4: remove all warnings Step 5: remove registries from tests Step 6: fix filter Step 7: private? -> !public? Step 8: Ash.Calculation -> Ash.Resource.Calculation Step 9: use depend_on_resources/1 -> resources/1 Step 10: add Domain to all resources Step 11: use Ash module for all actions Step 12: add public? true all around Step 13: remove verbose? from options passed during Domain calls Step 14: add simple_sat Step 15: Ash.ErrorKind is no more, so remove code from errors Step 16: sprinkle default_accept :* around tests Step 17: replace Ash.Changeset.new/2 with Ash.Changeset.for_* Step 18: calculation fixups - Context is now a struct and arguments go under the arguments key - Function based calculations receive a list of records - Add a select to query-based loads - select -> load Step 19: pass the correct name to pass the policy in tests Step 20: Ash.Query.new/2 is no more Step 21: add AshGraphql.Resource.embedded? utility function Use that instead of Ash.Type.embedded_type?(resource_or_type) since resources are not types anymore Step 22: handle struct + instance_of: Resource in unions Resources are not type anymore so they need to be passed this way in unions Step 23: ensure we only check GraphQL actions for pagination All reads are now paginated by default, so this triggered a compilation error Step 24: swap arguments for sort on calculations Step 25: remove unused debug? option
2024-04-02 07:03:06 +13:00
Add the following to your domain module. If you don't have one, be sure to start with the [Ash Getting Started Guide](https://hexdocs.pm/ash/get-started.html).
2020-08-14 10:55:34 +12:00
```elixir
defmodule Helpdesk.Support do
improvement!: port AshGraphql to Ash 3.0 (#123) Step 1: update Ash Step 2: mass rename Api to Domain Step 3: Ash.Query.expr -> Ash.Expr.expr Also change ref interpolation Step 4: remove all warnings Step 5: remove registries from tests Step 6: fix filter Step 7: private? -> !public? Step 8: Ash.Calculation -> Ash.Resource.Calculation Step 9: use depend_on_resources/1 -> resources/1 Step 10: add Domain to all resources Step 11: use Ash module for all actions Step 12: add public? true all around Step 13: remove verbose? from options passed during Domain calls Step 14: add simple_sat Step 15: Ash.ErrorKind is no more, so remove code from errors Step 16: sprinkle default_accept :* around tests Step 17: replace Ash.Changeset.new/2 with Ash.Changeset.for_* Step 18: calculation fixups - Context is now a struct and arguments go under the arguments key - Function based calculations receive a list of records - Add a select to query-based loads - select -> load Step 19: pass the correct name to pass the policy in tests Step 20: Ash.Query.new/2 is no more Step 21: add AshGraphql.Resource.embedded? utility function Use that instead of Ash.Type.embedded_type?(resource_or_type) since resources are not types anymore Step 22: handle struct + instance_of: Resource in unions Resources are not type anymore so they need to be passed this way in unions Step 23: ensure we only check GraphQL actions for pagination All reads are now paginated by default, so this triggered a compilation error Step 24: swap arguments for sort on calculations Step 25: remove unused debug? option
2024-04-02 07:03:06 +13:00
use Ash.Domain, extensions: [
AshGraphql.Domain
2020-08-14 10:55:34 +12:00
]
2020-09-24 12:54:57 +12:00
2020-08-14 10:55:34 +12:00
graphql do
improvement!: port AshGraphql to Ash 3.0 (#123) Step 1: update Ash Step 2: mass rename Api to Domain Step 3: Ash.Query.expr -> Ash.Expr.expr Also change ref interpolation Step 4: remove all warnings Step 5: remove registries from tests Step 6: fix filter Step 7: private? -> !public? Step 8: Ash.Calculation -> Ash.Resource.Calculation Step 9: use depend_on_resources/1 -> resources/1 Step 10: add Domain to all resources Step 11: use Ash module for all actions Step 12: add public? true all around Step 13: remove verbose? from options passed during Domain calls Step 14: add simple_sat Step 15: Ash.ErrorKind is no more, so remove code from errors Step 16: sprinkle default_accept :* around tests Step 17: replace Ash.Changeset.new/2 with Ash.Changeset.for_* Step 18: calculation fixups - Context is now a struct and arguments go under the arguments key - Function based calculations receive a list of records - Add a select to query-based loads - select -> load Step 19: pass the correct name to pass the policy in tests Step 20: Ash.Query.new/2 is no more Step 21: add AshGraphql.Resource.embedded? utility function Use that instead of Ash.Type.embedded_type?(resource_or_type) since resources are not types anymore Step 22: handle struct + instance_of: Resource in unions Resources are not type anymore so they need to be passed this way in unions Step 23: ensure we only check GraphQL actions for pagination All reads are now paginated by default, so this triggered a compilation error Step 24: swap arguments for sort on calculations Step 25: remove unused debug? option
2024-04-02 07:03:06 +13:00
authorize? false # Defaults to `true`, use this to disable authorization for the entire domain (you probably only want this while prototyping)
2020-08-14 10:55:34 +12:00
end
...
2020-08-14 10:55:34 +12:00
end
```
## Add graphql to your resources
Some example queries/mutations are shown below. If no queries/mutations are added, nothing will show up in the GraphQL API, so be sure to set one up if you want to try it out.
2020-08-14 10:55:34 +12:00
```elixir
defmodule Helpdesk.Support.Ticket. do
2020-08-14 10:55:34 +12:00
use Ash.Resource,
...,
2020-08-14 10:55:34 +12:00
extensions: [
AshGraphql.Resource
]
2020-09-24 12:54:57 +12:00
2020-08-14 10:55:34 +12:00
graphql do
type :ticket
2020-09-24 12:54:57 +12:00
2020-08-14 10:55:34 +12:00
queries do
# Examples
# create a field called `get_ticket` that uses the `read` read action to fetch a single ticke
get :get_ticket, :read
# create a field called `most_important_ticket` that uses the `most_important` read action to fetch a single record
read_one :most_important_ticket, :most_important
# create a field called `list_tickets` that uses the `read` read action to fetch a list of tickets
list :list_tickets, :read
2020-08-14 10:55:34 +12:00
end
2020-09-24 12:54:57 +12:00
2020-08-14 10:55:34 +12:00
mutations do
# Examples
create :create_ticket, :create
update :update_ticket, :update
destroy :destroy_ticket, :destroy
2020-08-14 10:55:34 +12:00
end
end
...
2020-08-14 10:55:34 +12:00
end
```
## Add AshGraphql to your schema
2022-09-07 10:24:02 +12:00
If you don't have an absinthe schema, you can create one just for ash.
in `lib/helpdesk/schema.ex`
2020-08-14 10:55:34 +12:00
```elixir
2024-04-12 03:48:09 +12:00
defmodule Helpdesk.GraphqlSchema do
2020-08-14 10:55:34 +12:00
use Absinthe.Schema
2024-04-12 03:48:09 +12:00
use AshGraphql, domains: [Helpdesk.Support]
2020-08-14 10:55:34 +12:00
# The query and mutation blocks is where you can add custom absinthe code
query do
end
mutation do
end
2020-08-14 10:55:34 +12:00
end
```
## Connect your schema
### Using Phoenix
2022-09-07 10:24:02 +12:00
You will simply want to add some code to your router, like so.
You will also likely want to set up the "playground" for trying things out.
2020-08-14 10:55:34 +12:00
```elixir
pipeline :graphql do
plug AshGraphql.Plug
end
scope "/" do
pipe_through [:graphql]
forward "/gql",
Absinthe.Plug,
schema: Module.concat(["Helpdesk.GraphqlSchema"])
forward "/playground",
Absinthe.Plug.GraphiQL,
schema: Module.concat(["Helpdesk.GraphqlSchema"]),
interface: :playground
end
2020-08-14 10:55:34 +12:00
```
> ### Whats up with `Module.concat/1`? {: .info}
>
2024-05-02 07:59:26 +12:00
> This `Module.concat/1` prevents a [compile-time dependency](https://dashbit.co/blog/speeding-up-re-compilation-of-elixir-projects) from this router module to the schema module. It is an implementation detail of how `forward/2` works that you end up with a compile-time dependency on the schema, but there is no need for this dependency, and that dependency can have _drastic_ impacts on your compile times in certain scenarios.
If you started with `mix new ...` instead of `mix phx.new ...` and you want to
still use phoenix, the fastest path that way is typically to just create a new
phoenix application and copy your resources/config over.
2023-02-21 05:52:47 +13:00
### Using Plug
If you are unfamiliar with how plug works, this [guide](https://elixirschool.com/en/lessons/specifics/plug/#dependencies) will be helpful for understanding it. It also guides you through
adding plug to your application.
Then you can use a `Plug.Router` and [forward](https://hexdocs.pm/plug/Plug.Router.html#forward/2) to your plugs similar to how it is done for phoenix:
```elixir
plug AshGraphql.Plug
forward "/gql",
to: Absinthe.Plug,
init_opts: [schema: Module.concat(["Helpdesk.GraphqlSchema"])]
forward "/playground",
to: Absinthe.Plug.GraphiQL,
init_opts: [
schema: Module.concat(["Helpdesk.GraphqlSchema"]),
interface: :playground
]
```
For information on why we are using `Module.concat/1`, see the note above in the Phoenix section.
2023-02-21 05:52:47 +13:00
## What's next?
Topics:
2023-02-21 05:52:47 +13:00
- [GraphQL Generation](/documentation/topics/graphql-generation.md)
How Tos:
2024-05-02 07:59:26 +12:00
- [Authorize With GraphQL](/documentation/topics/authorize-with-graphql.md)
- [Handle Errors](/documentation/topics/handle-errors.md)
- [Use Enums with GraphQL](/documentation/topics/use-enums-with-graphql.md)
- [Use JSON with GraphQL](/documentation/topics/use-json-with-graphql.md)
2023-02-21 05:52:47 +13:00
[Monitoring](/documentation/monitoring.md)