## File: README.md

# Absinthe

[](https://github.com/absinthe-graphql/absinthe/actions?query=workflow%3ACI)
[](https://hex.pm/packages/absinthe)
[](https://hexdocs.pm/absinthe/)
[](https://hex.pm/packages/absinthe)
[](https://opensource.org/licenses/MIT)
[](https://github.com/absinthe-graphql/absinthe/commits/main)

[GraphQL](https://graphql.org) implementation for Elixir.

Goals:

- Complete implementation of the [GraphQL Working Draft](https://spec.graphql.org/draft/).
- An idiomatic, readable, and comfortable API for Elixir developers
- Extensibility based on small parts that do one thing well.
- Detailed error messages and documentation.
- A focus on robustness and production-level performance.

Please see the website at [https://absinthe-graphql.org](https://absinthe-graphql.org).

## Why Use Absinthe?

Absinthe goes far beyond GraphQL specification basics.

### Easy-to-Read, Fast-to-Run Schemas

Absinthe schemas are defined using easy-to-read macros that build and verify
their structure at compile-time, preventing runtime errors and increasing
performance.

### Pluggability

The entire query processing pipeline is configurable. Add, swap out, or remove
the parser, individual validations, or resolution logic at will, even on a
per-document basis.

### Advanced Resolution

Absinthe includes a number of advanced resolution features, to include:

- Asynchronous field resolution
- Batched field resolution (addressing N+1 query problems)
- A resolution plugin system supporting further extensibility

### Safety

- Complexity analysis and configurable limiting
- Support for precompiled documents/preventing custom documents

### Idiomatic Documents, Idiomatic Code

Write your schemas in idiomatic Elixir `snake_case` notation. Absinthe can
transparently translate to `camelCase` notation for your API clients.

Or, define your own translation schema by writing a simple adapter.

### Frontend Support

We care about support for third-party frameworks, both on the back and
front end.

So far, we include specialized support for Phoenix and Plug on the backend,
and [Relay](https://relay.dev/) on the frontend.

Of course we work out of the box with other frontend frameworks and GraphQL
clients, too.

## Installation

Install from [Hex.pm](https://hex.pm/packages/absinthe):

```elixir
def deps do
  [{:absinthe, "~> 1.7.0"}]
end
```

Note: Absinthe requires Elixir 1.10 or higher.

## Upgrading

See [CHANGELOG](./CHANGELOG.md) for upgrade steps between versions.

## Documentation

- [Absinthe hexdocs](https://hexdocs.pm/absinthe).
- For the tutorial, guides, and general information about Absinthe-related
  projects, see [https://absinthe-graphql.org](https://absinthe-graphql.org).

### Mix Tasks

Absinthe includes a number of useful Mix tasks for extracting schema metadata.

Run `mix help` in your project and look for tasks starting with `absinthe`.

## Related Projects

See the [GitHub organization](https://github.com/absinthe-graphql).

## Community

The project is under constant improvement by a growing list of
contributors, and your feedback is important. Please join us in Slack
(`#absinthe-graphql` under the Elixir Slack account) or the Elixir Forum
(tagged `absinthe`).

Please remember that all interactions in our official spaces follow
our [Code of Conduct](./CODE_OF_CONDUCT.md).

## Contribution

Please follow [contribution guide](./CONTRIBUTING.md).

## License

See [LICENSE.md](./LICENSE.md).

---

## File: guides/client/apollo.md

# Using with Apollo Client

An Apollo client manages its connection to the GraphQL server using [links](https://www.apollographql.com/docs/link/) -- which are essentially middleware that tell Apollo how to resolve each query. You can configure Apollo to connect to your Absinthe server via HTTP, websockets, or both.

## Using an HTTP link

Using Apollo with an HTTP link does not require any Absinthe-specific configuration. You can create an HTTP link pointed at your Absinthe server as follows:

```javascript
import { ApolloClient, InMemoryCache, createHttpLink } from "@apollo/client";

// Create an HTTP link to the Absinthe server.
const link = createHttpLink({
  uri: "http://localhost:4000/graphql"
});

// Apollo also requires you to provide a cache implementation
// for caching query results. The InMemoryCache is suitable
// for most use cases.
const cache = new InMemoryCache();

// Create the client.
const client = new ApolloClient({
  link,
  cache
});
```

You may find that you need to modify the HTTP request that Apollo makes -- for example, if you wish to send the value of a particular cookie in the `Authorization` header. The `setContext` helper allows you to do this, and also demonstrates how links in Apollo can be chained.

```javascript
import { ApolloClient, InMemoryCache, createHttpLink } from "@apollo/client";
import { setContext } from "@apollo/client/link/context";
import Cookies from "js-cookie";

// Create an HTTP link to the Absinthe server.
const httpLink = createHttpLink({
  uri: "http://localhost:4000/graphql"
});

// Use setContext to create a chainable link object that sets
// the token cookie to the Authorization header.
const authLink = setContext((_, { headers }) => {
  // Get the authentication token from the cookie if it exists.
  const token = Cookies.get("token");

  // Add the new Authorization header.
  return {
    headers: {
      ...headers,
      authorization: token ? `Bearer ${token}` : ""
    }
  };
});

// Chain the HTTP link and the authorization link.
const link = authLink.concat(httpLink);

// Apollo also requires you to provide a cache implementation
// for caching query results. The InMemoryCache is suitable
// for most use cases.
const cache = new InMemoryCache();

// Create the client.
const client = new ApolloClient({
  link,
  cache
});
```

## Using a websocket link

An HTTP link is suitable for many basic use cases, but if you require two-way communication between the server and the client, you will need to use a websocket link. The most common use case is a client that needs to use GraphQL subscriptions to receive updates from the server when particular events occur. To implement a websocket link, we will need to use the [`@absinthe/socket`](https://www.npmjs.com/package/@absinthe/socket) and [`@absinthe/socket-apollo-link`](https://www.npmjs.com/package/@absinthe/socket-apollo-link) packages.

```javascript
import { ApolloClient, InMemoryCache } from "@apollo/client";
import * as AbsintheSocket from "@absinthe/socket";
import { createAbsintheSocketLink } from "@absinthe/socket-apollo-link";
import { Socket as PhoenixSocket } from "phoenix";
import Cookies from "js-cookie";

// Create a standard Phoenix websocket connection. If you need
// to provide additional params, like an authentication token,
// you can configure them in the `params` option.
const phoenixSocket = new PhoenixSocket("ws://localhost:4000/socket", {
  params: () => {
    if (Cookies.get("token")) {
      return { token: Cookies.get("token") };
    } else {
      return {};
    }
  }
});

// Wrap the Phoenix socket in an AbsintheSocket.
const absintheSocket = AbsintheSocket.create(phoenixSocket);

// Create an Apollo link from the AbsintheSocket instance.
const link = createAbsintheSocketLink(absintheSocket);

// Apollo also requires you to provide a cache implementation
// for caching query results. The InMemoryCache is suitable
// for most use cases.
const cache = new InMemoryCache();

// Create the client.
const client = new ApolloClient({
  link,
  cache
});
```

### Reconnecting the websocket link

You may find that you periodically need to reconnect the websocket with different parameters. The most common case for this is when a user logs in or logs out; you will then want to refresh their subscriptions to reflect the new authentication state. You can accomplish this by invoking `phoenixSocket.conn.close();` from your application code whenever the reconnection needs to happen. Phoenix will notice the closed connection and automatically reconnect. It is important that you provide a function that returns the websocket parameters to the socket `params` option. If you provide the parameters directly as an object, the new parameters will not be picked up when the websocket reconnects, but if you provide a function, Phoenix invokes the function on each connection to obtain the parameters.

Note that this solution (reconnecting with `phoenixSocket.conn.close();`) is somewhat unstable because it relies upon an implementation detail of the Phoenix socket. Ideally, a future version of the Phoenix package might add a public API method to reconnect the websocket with new parameters.

```javascript
import { ApolloClient, InMemoryCache } from "@apollo/client";
import * as AbsintheSocket from "@absinthe/socket";
import { createAbsintheSocketLink } from "@absinthe/socket-apollo-link";
import { Socket as PhoenixSocket } from "phoenix";
import Cookies from "js-cookie";

// Create a standard Phoenix websocket connection. If you need
// to provide additional params, like an authentication token,
// you can configure them in the `params` option.
//
// If you plan to reconnect the socket with updated parameters,
// you must provide a function to the `params` option. If you
// provide the parameters directly as an object, the updated
// parameters will not be picked up when the socket reconnects.
const phoenixSocket = new PhoenixSocket("ws://localhost:4000/socket", {
  params: () => {
    if (Cookies.get("token")) {
      return { token: Cookies.get("token") };
    } else {
      return {};
    }
  }
});

// Wrap the Phoenix socket in an AbsintheSocket.
const absintheSocket = AbsintheSocket.create(phoenixSocket);

// Create an Apollo link from the AbsintheSocket instance.
const link = createAbsintheSocketLink(absintheSocket);

// Apollo also requires you to provide a cache implementation
// for caching query results. The InMemoryCache is suitable
// for most use cases.
const cache = new InMemoryCache();

// Create the client.
const client = new ApolloClient({
  link,
  cache
});

// Later in your application code, when you need to reconnect
// the socket.
phoenixSocket.conn.close();
```

## Using both HTTP and websocket links

A common configuration for Apollo client applications is to use both HTTP and websocket links -- HTTP for queries and mutations, and a websocket for subscriptions. We can implement this in our client using [directional composition with Apollo's `split` helper](https://www.apollographql.com/docs/react/api/link/introduction/#directional-composition).

```
/* Detailed source-code truncated for AI context efficiency. */
```

---

## File: guides/client/javascript.md

# Using with JavaScript

You can interact with an Absinthe GraphQL server via HTTP (thanks to
`absinthe_plug`) and websockets (thanks to `absinthe_phoenix`):

We also have special support for configuring and working with specific
JavaScript frameworks. You can see the guides here:

- [Apollo Client](apollo.md)
- [Relay](relay.md)

## Over HTTP

To integrate a JavaScript application via HTTP, any standard GraphQL
HTTP request (GET/POST) will do.

Here's an example using
[isomorphic-fetch](https://www.npmjs.com/package/isomorphic-fetch):

``` javascript
require('isomorphic-fetch');

fetch('http://localhost:4000/graphql', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({ query: '{ posts { title } }' }),
})
  .then(res => res.json())
  .then(res => console.log(res.data));
```

## Over Websockets

See the [@absinthe/socket](https://github.com/absinthe-graphql/absinthe-socket/tree/master/packages/socket) NPM package
for special support for Absinthe's use of Phoenix channels for GraphQL over websockets, including support for
[subscriptions](subscriptions.md).

---

## File: guides/client/relay.md

# Using with Relay

While GraphQL specifies what queries, mutations, and object types should look
like, Relay is a client-side implementation of an efficient data storage and
(re-)fetching system that is designed to work with a GraphQL server.

To allow Relay to work its magic on the client side, all GraphQL queries and
mutations need to follow certain conventions. `Absinthe.Relay` provides
utilities to help you make your server-side schemas Relay-compatible while
requiring only minimal changes to your existing code.

`Absinthe.Relay` supports three fundamental pieces of the Relay puzzle: *nodes*,
which are normal GraphQL objects with a unique global ID scheme; *mutations*,
which in Relay Classic conform to a certain input and output structure; and
*connections*, which provide enhanced functionality around many-to-one lists
(most notably pagination).

## Using Absinthe.Relay

Make sure you have the [absinthe_relay](https://hex.pm/packages/absinthe_relay)
package [configured](https://github.com/absinthe-graphql/absinthe_relay#installation)
as a dependency for your application.

To add Relay support schemas should start with `use Absinthe.Relay.Schema`, eg:

```elixir
defmodule Schema do
  use Absinthe.Schema
  use Absinthe.Relay.Schema, :classic

  # ...

end
```

> Note that this schema is being prepared to support Relay Classic; if
> you do not provide either a `:classic` or `:modern` option,
> `:classic` is currently selected as the default, but a warning is
> output; `:modern` will be the default option in v1.5.

If you're defining your types in a separate type module that you're using via
`import_types` in your schema, use the `Notation` module instead:

```elixir
defmodule Schema.Types do
  use Absinthe.Schema.Notation
  use Absinthe.Relay.Schema.Notation, :classic

  # ...

end
```

Now you're ready to implement the Relay features you need.

## Nodes

To enable Relay to be clever about caching and (re-)fetching data objects, your
server must assign a globally unique ID to each object before sending it down
the wire. Absinthe will take care of this for you if you provide some additional
information in your schema.

First of all, you must define a `:node` interface in your schema. Rather than
do this manually, `Absinthe.Relay` provides a macro so most of the configuration
is handled for you.

Use `node interface` in your schema:

```elixir
node interface do
  resolve_type fn
    %YourApp.Model.Person{}, _ ->
      :person
    %YourApp.Model.Business{}, _ ->
      :business
    _, _ ->
      nil
  end
end

# ... mutations, queries ...
```

For instance, if your query or mutation resolver returns:

```elixir
{:ok, %YourApp.Model.Business{id: 19, business_name: "ACME Corp.", employee_count: 52}}
```

Absinthe will pattern-match the value to determine that the object type is
`:business`. This becomes important when you configure your `:business` type as a `node`:

```elixir
node object :business do  # <-- notice the macro prefix "node"
  field :business_name, non_null(:string)
  field :employee_count, :integer
end
```

(Note the macro name, `node`, looks like a prefix to the `object` macro.)

While it may appear that your `:business` object type only has two fields,
`:business_name` and `:employee_count`, it actually has _three_. An `:id` field
is configured for you because you used the `node object` macro, and because the
`:node` interface knows how to identify the values returned from your resolvers,
that `:id` field is automatically set-up to convert internal (in this case,
numeric) IDs to the global ID scheme -- an opaque string (like `"UWxf59AcjK="`)
will be returned instead.


**Important:** the global ID is generated based on the object's
unique identifier, which by default is **the value of its existing `:id`
field**. This is convenient, because if you are using Ecto, the
primary key `:id` database field is typically enough to uniquely identify an
object of a given type. It also means, however, that *the internal `:id` of a
node object will not be available to be queried as `:id`.*


- If you wish to generate your global IDs based on something other than the
  existing `:id` field (if, for instance, your internal IDs are returned as `_id`),
  provide the `:id_fetcher` option (see the [documentation](https://hexdocs.pm/absinthe_relay/Absinthe.Relay.Node.html)).
- If you wish to make your internal ID queryable, you must return it as a
  different field (eg, you could define an `:internal_id` field whose resolver
  extracts the raw, internal `:id` value from the source map/struct).

### Node query field

Ok, so your node objects provide a global `:id`. How does Relay use it?

Relay expects you to provide a query field called `node` that accepts a global
ID (as arg `:id`) and returns the corresponding node object. Absinthe makes it
easy to set this up -- use the `node field` macro inside your `query`.

```elixir
query do
  # ...
  node field do
    resolve fn
      %{type: :person, id: id}, _ ->
        # Get the person from the DB somehow, returning a tuple
        YourApp.Resolver.Person.find(%{id: id}, %{})
      %{type: :business, id: id}, _ ->
        # Get the business from @businesses
        {:ok, Map.get(@businesses, id)}
      # etc.
    end
  end
  # ... more queries ...
end
```

Notice that the resolver for `node field` expects the first (args) argument to
contain a `:type` and `:id`. These are the node object type identifier and the
internal (non-global) ID, automatically parsed from the global ID. The resolver
looks up the correct value using the internal ID and returns a tuple, as usual.

For more information, see the [documentation](https://hexdocs.pm/absinthe_relay/Absinthe.Relay.Node.html).

### Converting node IDs to internal IDs for resolvers

If you need to parse a node (global) ID for use in a resolver, there is a
helpful utility, `parsing_node_ids/2` that is automatically imported for you.
Here's an example of how it works.

Let's assume we have a field, `:employees`, that returns a list of `:person`
objects for a given `:business_id` -- a node ID:

```elixir
query do
  field :employees, list_of(:people) do
    arg :business_id, :id
    resolve &resolve_employees/2
  end
end

def resolve_employees(%{business_id: global_id}, _) do
  # But I need an internal ID to look-up the employees!
end
```

In `resolve_employees/2`, we could certainly parse out the internal ID manually.
Here's how that would look:

```elixir
def resolve_employees(%{business_id: global_id}, _) do
  {:ok, %{type: :business, id: internal_id}} =
    Absinthe.Relay.Node.from_global_id(global_id, YourApp.Schema)
  # TODO: find employees using internal_id, return tuple
end
```

Obviously this can get a bit tedious if we have to do it often. Instead, we can
use `parsing_node_ids/2` to _wrap_ our resolver function to do the parsing for
us, invoking our function with the internal ID instead. We just have to tell the
`parsing_node_ids/2` what ID field arguments to parse and what the associated
types should be:

```elixir
query do
  field :employees, list_of(:people) do
    arg :business_id, :id
    resolve parsing_node_ids(&resolve_employees/2, business_id: :business)
  end
end

def resolve_employees(%{business_id: internal_id}, _) do
  # We have an internal ID!
end
```

This leaves our resolver function virtually unchanged, and keeps our code much
cleaner.

## Mutations

Relay Classic sets some specific constraints around the way arguments and results for
mutations are structured.

> In Relay Modern (if you're using the `:modern` option when defining
> the schema), you'll have access to a similar set of macros as
> discussed here, but be aware that the constraints mentioned (on
> `input`, on `clientMutationId`, etc) don't apply. See the
> documentation for [Absinthe.Relay.Mutation.Notation.Modern](https://hexdocs.pm/absinthe_relay/Absinthe.Relay.Mutation.Notation.Modern.html) for more
> specific instructions.

Relay expects mutations to accept exactly one argument, `input`, an
`InputObject`. On the JavaScript side, it automatically populates a field on the
input, `clientMutationId`, and expects to get it back, unchanged, as part of the
result. Thankfully `Absinthe.Relay` abstracts these details away from the schema
designer, allowing them to focus on any _other_ arguments needed or results
expected.


**Important:** Remember that input fields (and arguments in
general) cannot be of one of your `object` types. Use `input_object` to
model complex argument types.


In this example, we accept a list of multiple `:person_input_object` values to
insert people into a database.

```elixir
defmodule YourApp.Schema do
  # ...

  input_object :person_input_object do
    field :first_name, non_null(:string)
    field :last_name, non_null(:string)
    field :age, :integer
  end

  mutation do

    @desc "A mutation that inserts a list of persons into the database"
    payload field :bulk_create_persons do
      input do
        field :persons, list_of(:person_input_object)
      end
      output do
        # fields in the result
      end
      resolve &Resolver.Person.bulk_create/2
    end

    # ... more mutations ...
  end
end
```

Note the `payload` macro introduces a Relay mutation, `input` defines the fields
(inside the `input` argument), and `output` defines the fields available as part
of the result.

See the module documentation for more information:

- [Absinthe.Relay.Mutation.Notation.Classic](https://hexdocs.pm/absinthe_relay/Absinthe.Relay.Mutation.Notation.Classic.html)
- [Absinthe.Relay.Mutation.Notation.Modern](https://hexdocs.pm/absinthe_relay/Absinthe.Relay.Mutation.Notation.Modern.html)

### Referencing existing nodes in mutation inputs

Occasionally, your client may wish to make reference to an existing node in the
mutation input (this happens particularly when manipulating the connection edges
of a parent node).

Incoming IDs for node types may have to be converted to their internal
equivalents so you can persist changes to your backend. For this purpose, you
can use `Absinthe.Relay.Node.from_global_id/2` to parse node (global) IDs
manually.

```elixir
def bulk_create(%{persons: new_persons, group: global_group_id}, _) do
  {:ok, %{type: :group, id: internal_group_id}} = Absinthe.Relay.Node.from_global_id(global_group_id, YourApp.Schema)
  # ... manipulate your DB using internal_group_id
end
```

If, of course, your client knows the internal IDs (in a peer field to `:id`, eg,
`:internal_id`), you can depends on that ID -- but we recommend that you use
node IDs as they are opaque values and it's the more conventional practice.


**Important:** When using `from_global_id`, remember to always
match the `:type` value to ensure the internal ID is for the type you expect,
and a global ID for the wrong type of node hasn't been mistakenly sent to the
server.


## Connections

One of the more popular features of Relay is the rich pagination support provided by its
connections. [This medium post](https://dev-blog.apollodata.com/explaining-graphql-connections-c48b7c3d6976)
has a good explanation of the full feature set and nomenclature.

For example, you could define a connection for paginating `:location` objects with:

`connection node_type: :location`

This will automatically define two new types: `:location_connection` and `:location_edge`.

We define a field that uses these types to paginate associated records by using
`connection field`. Here, for instance, we support paginating a business’s locations:

```elixir
object :business do
  field :short_name, :string
  connection field :locations, node_type: :location do
    resolve fn
      pagination_args, %{source: business} ->
        Location
        |> where(business_id: ^business.id)
        |> order_by(:inserted_at)
        |> Connection.from_query(&Repo.all/1, pagination_args)
    end
  end
end
```

We are piping a query for the associated locations into `from_query/3` along with the default
relay pagination arguments that allow for pagination. For example, to get just the first 10
locations, use the `first` argument:

```graphql
query {
  business(id:"9ea6605e-e6c8-44ea-98d0-1fe6276e193d") {
    shortName
    locations(first:10) {
      edges
        node {
          address1
          city
        }
      }
    }
  }
}
```

Check the [documentation](https://hexdocs.pm/absinthe_relay/Absinthe.Relay.Connection.html)
for more details on connections.


**Note:** These features do not require using Relay on the client as Apollo
and other client implementations generally support Relay connection configuration.

---

## File: guides/introduction/community.md

# Community

## Twitter

Follow the project on Twitter as [`@absinthegraphql`](https://twitter.com/absinthegraphql) for news and additional resources.

## Chat

You can find the maintainers and an active community of users and contributors in the `#absinthe-graphql` channel in the [Elixir](https://elixir-slackin.herokuapp.com/) Slack.

## Forum

Questions and suggestions can be submitted on the [Elixir Forum](https://elixirforum.com). Please categorize/tag as `Absinthe`.

---

## File: guides/introduction/installation.md

# Installation

To install Absinthe, just add an entry to your `mix.exs`:

```elixir
def deps do
  [
    # ...
    {:absinthe, "~> 1.7"}
  ]
end
```

(Check [Hex](https://hex.pm/packages/absinthe) to make sure you're using an up-to-date version number.)

## Overriding Dependencies

Because the Absinthe project is made up of a large number of related packages to support integrations with other tools, sometimes you may want to update only part of your absinthe-related dependencies.

Don't forget you can use the [:override](https://hexdocs.pm/mix/Mix.Tasks.Deps.html#module-dependency-definition-options) option for your Mix dependencies if you'd like to ensure a specific package is at a specific version number. For example, If you wanted to try a new version of Absinthe without updating something that depends on it (which is locked to an older version):

```elixir
def deps do
  [
    # ...
    {:absinthe, "~> 1.7", override: true}
  ]
end
```

## Plug, Phoenix, and GraphiQL

Most people use Absinthe to support an HTTP API.

You'll want to read the [Plug and Phoenix](plug-phoenix.md) for specific installation and configuration options, including how you can run the handy, included GraphiQL tool directly from your application.

---

## File: guides/introduction/learning.md

# Learning

The following are some Absinthe-specific educational resources that are available.

## Books

* [Craft GraphQL APIs in Elixir with Absinthe](https://pragprog.com/titles/wwgraphql/craft-graphql-apis-in-elixir-with-absinthe/) by the creators of Absinthe.

## Online Resources

* [Website](https://absinthe-graphql.org) (mostly just links elsewhere)
* [Documentation](https://hexdocs.pm/absinthe) (current stable release)
* [How to GraphQL (with Absinthe)](https://www.howtographql.com/graphql-elixir/0-introduction/)

## Videos

* [Live APIs with GraphQL Subscriptions](https://www.youtube.com/watch?v=PEckzwggd78), ElixirConf 2017 (Bellevue)
* [GraphQL in Practice](https://www.youtube.com/watch?v=d2qNlXtpWXM), ElixirConf EU 2017 (Barcelona)

## General GraphQL Information

There's a ton of GraphQL resources on the web.

The [official website](https://graphql.org/) and [How to GraphQL](https://www.howtographql.com) are good places to start.

---

## File: guides/introduction/overview.md

# Overview

Absinthe is the GraphQL toolkit for Elixir, an implementation of the [GraphQL specification](https://spec.graphql.org) built to suit the language's capabilities and idiomatic style.

The Absinthe project consists of several complementary packages. You can find the full listing on the [absinthe-graphql](https://github.com/absinthe-graphql) GitHub organization page.

## GraphQL Basics

If you're new to GraphQL, we suggest you read up a bit on GraphQL's foundational principles before you dive into Absinthe.

Here are a few resources that might be helpful:

- The official [GraphQL](https://graphql.org/) website
- [How to GraphQL](https://www.howtographql.com/), which includes a [brief tutorial](https://www.howtographql.com/graphql-elixir/0-introduction/) using Absinthe

## Absinthe

Absinthe's functionality generally falls into two broad areas. You can read more about the details in the guides provided as part of this documentation and in the related packages/projects:

* [Defining Schemas](schemas.md). A schema:
  * defines the structure of data entities and the relationships between, as well as the available queries, mutations, and subscriptions, using an elegant collection of declarative macros
  * defines [custom scalar](custom-scalars.md) types
  * declares any [deprecated](directives.md) definitions, and applies other [directives](directives.md)
  * defines resolution functions to access data, using a flexible and extensible middleware/plugin system
* Executing Documents. A GraphQL document:
  * can be any standard GraphQL query, mutation, or subscription
  * may include reusable [variable](variables.md) definitions
  * can be analyzed for its [complexity](complexity-analysis.md) and be rejected if it's unsafe/too expensive
  * has a [context](context-and-authentication.md) that you can integrate with authentication and authorization strategies
  * can contain standard GraphQL [introspection](introspection.md) fields
  * can include multipart file uploads as GraphQL arguments (as part of the [absinthe_plug](https://hex.pm/packages/absinthe_plug) package)

## Integrations

Absinthe integrates with a number of other important projects, both on the backend and frontend, to provide a better experience for developers.

* Elixir
  * Support for HTTP APIs using [Plug and Phoenix](plug-phoenix.md) via the [absinthe_plug](https://hex.pm/packages/absinthe_plug) and [absinthe_phoenix](https://hex.pm/packages/absinthe_phoenix) packages
  * Support for [Ecto](https://hex.pm/packages/ecto) via the [dataloader](https://github.com/absinthe-graphql/dataloader) package
* JavaScript (client-side)
  * Support for [Relay](relay.md) and [Apollo Client](apollo.md)
  * Support for Absinthe's channel-based subscriptions. See [absinthe-socket](https://github.com/absinthe-graphql/absinthe-socket).

## Guides

To contribute to the guides, please submit a pull request to the [absinthe](https://github.com/absinthe-graphql/absinthe) project on GitHub.

You'll find the content under `guides/`.

---

## File: guides/tutorial/complex-arguments.md

# Complex Arguments

In preparation for supporting comments on our blog, let's create users. We're building
a modern mobile first blog of course, and thus want to support either a phone number
or an email as the contact method for a user.

We want to support the following mutations.

Support creation of a user with their email address:

```graphql
mutation CreateEmailUser {
  createUser(
    contact: { type: EMAIL, value: "foo@bar.com" }
    name: "Jane"
    password: "hunter1"
  ) {
    id
    contacts {
      type
      value
    }
  }
}
```

And by using their phone number:

```graphql
mutation CreatePhoneUser {
  createUser(
    contact: { type: PHONE, value: "+1 123 5551212" }
    name: "Joe"
    password: "hunter2"
  ) {
    id
    contacts {
      type
      value
    }
  }
}
```

To do this we need the ability to create nested arguments. GraphQL has input objects
for this purpose. Input objects, like regular object, contain key value pairs, but
they are intended for input only (you can't do circular references with them for example).

Another notion we'll look at here is an enumerable type. We only want to support contact
types `"email"` and `"phone"` at the moment, and GraphQL gives us the ability to
specify this in our schema.

Let's start with our `:contact_type` Enum. In `blog_web/schema/account_types.ex`:

```graphql
enum :contact_type do
  value :phone, as: "phone"
  value :email, as: "email"
end
```

We're using the `:as` option here to make sure the parsed enum is represented by a string
when it's passed to our controllers; this is to ease integration with our Ecto schema
(by default, the enum values are passed as atoms).

> #### Note {: .neutral}
>
> The standard convention for representing incoming enum values in
> GraphQL documents are in all caps. For instance, given our settings
> here, the accepted values would be `PHONE` and `EMAIL` (without
> quotes). See the GraphQL document examples above for examples.
>
> While the `enum` macro supports configuring this incoming format, we
> highly recommend you just use the GraphQL convention.

Now if a user tries to send some other kind of contact type they'll
get a nice error without any extra effort on your part. Enum types are
not a substitute for modeling layer validations however, be sure to
still enforce things like this on that layer too.

Now for our contact input object.

In `blog_web/schema/account_types.ex`:

```graphql
input_object :contact_input do
  field :type, non_null(:contact_type)
  field :value, non_null(:string)
end
```

Note that we name this type `:contact_input`. Input object types have
their own names, and the `_input` suffix is common.

> #### Important {: .tip}
>
> It's very important to remember that only input
> types---basically scalars and input objects---can be used to model
> input.

Finally our schema, in `blog_web/schema.ex`:

```elixir
mutation do

  #... other mutations

  @desc "Create a user"
  field :create_user, :user do
    arg :name, non_null(:string)
    arg :contact, non_null(:contact_input)
    arg :password, non_null(:string)

    resolve &Resolvers.Accounts.create_user/3
  end

end
```

Suppose in our database that we store contact information in a different database
table. Our mutation would be used to create both records in this case.

There does not need to be a one to one correspondence between how data is structured
in your underlying data store and how things are presented by your GraphQL API.

Our resolver, `blog_web/resolvers/accounts.ex` might look something like this:

```elixir
def create_user(_parent, args, %{context: %{current_user: %{admin: true}}}) do
  Blog.Accounts.create_user(args)
end
def create_user(_parent, args, _resolution) do
  {:error, "Access denied"}
end
```

You'll notice we're checking for `:current_user` again in our Absinthe
context, just as we did before for posts. In this case we're taking
the authorization check a step further and verifying that only
administrators (in this simple example, an administrator is a user
account with `:admin` set to `true`) can create a user.

Everyone else gets an `"Access denied"` error for this field.

> #### Note {: .neutral}
>
> To see the Ecto-related implementation of the
> `Blog.Accounts.create_user/1` function and the (stubbed) authentication logic we're
> using for this example, see the [absinthe_tutorial](https://github.com/absinthe-graphql/absinthe_tutorial)
> repository.

Here's our mutation in action in GraphiQL.



> #### Note {: .neutral}
>
> Note we're sending a `Authorization` header to authenticate, which a
> plug is handling. Make sure to read the
> related [guide](context-and-authentication.md) for more
> information on how to set-up authentication in your own
> applications.
>
> Our simple tutorial application is just using a simple stub: any
> authorization token logs you in the first user. Obviously not what
> you want in production!

## Next Step

Now let's [wrap things up](conclusion.md).

---

## File: guides/tutorial/conclusion.md

# Conclusion

With this we have a basic GraphQL based API for a blog. Head on over
to [the github page](https://github.com/absinthe-graphql/absinthe_tutorial) if
you want the final code.

We hope to expand this tutorial to include a comment system that will
acquaint you with Union types and Fragments in the coming days.

Head on over to the topic guides for further reading, and see
the [community page](community.md) for information
on how to get help, ask questions, or contribute!

## Please Help!

This tutorial is a work in progress, and while it covers the basics of
using Absinthe, there is plenty more that can be added and improved
upon. It's important that it's kept up-to-date, too, so if you notice
something that's slipped by us, please help us fix it!

Please contribute your GitHub issues (and pull requests!):

- The tutorial text is under `guides/tutorial` in the [absinthe](https://github.com/absinthe-graphql/absinthe)
  repository. It's in Markdown and easy to edit!
- The tutorial code located in the [absinthe_tutorial](https://github.com/absinthe-graphql/absinthe_tutorial) repository.