---
id: tutorial-todo-gql-mutation-input
title: Mutation Inputs
sidebar_label: Mutation Inputs
---

In this section, we continue the [GraphQL example](tutorial-todo-gql.md) by explaining how to extend the Ent code
generator using Go templates and generate [input type](https://graphql.org/graphql-js/mutations-and-input-types/)
objects for our GraphQL mutations that can be applied directly on Ent mutations.

#### Clone the code (optional)

The code for this tutorial is available under [github.com/a8m/ent-graphql-example](https://github.com/a8m/ent-graphql-example),
and tagged (using Git) in each step. If you want to skip the basic setup and start with the initial version of the GraphQL
server, you can clone the repository and run the program as follows:

```console
git clone git@github.com:a8m/ent-graphql-example.git
cd ent-graphql-example 
go run ./cmd/todo/
```

## Go Templates

The Ent framework accepts external templates that can extend or override the default generated functionality of its 
code generator. In the template below, we generate 2 input types (`CreateTodoInput` and `UpdateTodoInput`) for the
GraphQL mutations, and add additional methods on the different builders to accept these objects as an input type.

```gotemplate
{{ range $n := $.Nodes }}
    {{ $input := print "Create" $n.Name "Input" }}
    // {{ $input }} represents a mutation input for creating {{ plural $n.Name | lower }}.
    type {{ $input }} struct {
        {{- range $f := $n.Fields }}
            {{ $f.StructField }} {{ if and (or $f.Optional $f.Default) (not $f.Type.RType.IsPtr) }}*{{ end }}{{ $f.Type }}
        {{- end }}
        {{- range $e := $n.Edges }}
            {{- if $e.Unique }}
                {{ $e.StructField }} {{ if $e.Optional }}*{{ end }}{{ $e.Type.ID.Type }}
            {{- else }}
                {{ $e.StructField }} []{{ $e.Type.ID.Type }}
            {{- end }}
        {{- end }}
    }

    {{/* Additional methods go here.  */}}

    {{ $input = print "Update" $n.Name "Input" }}
    // {{ $input }} represents a mutation input for updating {{ plural $n.Name | lower }}.
    type {{ $input }} struct {
        {{- range $f := $n.MutableFields }}
            {{ $f.StructField }} {{ if not $f.Type.RType.IsPtr }}*{{ end }}{{ $f.Type }}
            {{- if $f.Optional }}
                {{ print "Clear" $f.StructField }} bool
            {{- end }}
        {{- end }}
        {{- range $e := $n.Edges }}
            {{- if $e.Unique }}
                {{ $e.StructField }} *{{ $e.Type.ID.Type }}
                {{ $e.MutationClear }} bool
            {{- else }}
                {{ $e.MutationAdd }} []{{ $e.Type.ID.Type }}
                {{ $e.MutationRemove }} []{{ $e.Type.ID.Type }}
            {{- end }}
        {{- end }}
    }

    {{/* Additional methods go here.  */}}
{{ end }}
```

The full version of this template exists in the [github.com/a8m/ent-graphql-example/ent/template](https://github.com/a8m/ent-graphql-example/blob/master/ent/template/mutation_input.tmpl).

:::info
If you have no experience with Go templates or if you have not used it before with the Ent code generator, go to the
[template documentation](templates.md) to learn more about it.

The full documentation for the template API (Go types and functions) is available in the
[pkg.go.dev/entgo.io/ent/entc/gen](https://pkg.go.dev/entgo.io/ent/entc/gen).
:::

Now, we tell the Ent code generator to execute this template by passing it as an argument in the `ent/entc.go` file:

```go {8} title="ent/entc.go"
func main() {
	ex, err := entgql.NewExtension()
	if err != nil {
		log.Fatalf("creating entgql extension: %v", err)
	}
	opts := []entc.Option{
		entc.Extensions(ex),
		entc.TemplateDir("./template"),
	}
	if err := entc.Generate("./schema", &gen.Config{}, opts...); err != nil {
		log.Fatalf("running ent codegen: %v", err)
	}
} 
```

After adding the template file to the `ent/template/` directory and changing the `entc.go` configuration, we're ready
to execute the code generation as follows:

```
go generate ./...
```

You may have noticed that Ent generated a new file `ent/mutation_input.go` with the following content:

```go
// Code generated by entc, DO NOT EDIT.

package ent

import (
	"time"
	"todo/ent/todo"
)

// CreateTodoInput represents a mutation input for creating todos.
type CreateTodoInput struct {
	Text      string
	CreatedAt time.Time
	Status    todo.Status
	Priority  int
	Children  []int
	Parent    *int
}

// Mutate applies the CreateTodoInput on the TodoCreate builder.
func (i *CreateTodoInput) Mutate(m *TodoCreate) {
	// ...
}

// UpdateTodoInput represents a mutation input for updating todos.
type UpdateTodoInput struct {
	Text           *string
	Status         *todo.Status
	Priority       *int
	AddChildIDs    []int
	RemoveChildIDs []int
	Parent         *int
	ClearParent    bool
}

// Mutate applies the UpdateTodoInput on the TodoMutation.
func (i *UpdateTodoInput) Mutate(m *TodoMutation) {
	// ...
}
```

## Input Types In GraphQL Schema

The new generated Go types are the GraphQL mutation types. Let's define them manually in the GraphQL schema and `gqlgen`
will map them automatically.

```graphql
# Define an input type for the mutation below.
# https://graphql.org/learn/schema/#input-types
#
# Note that, this type is mapped to the generated
# input type in mutation_input.go.
input CreateTodoInput {
    status: Status! = IN_PROGRESS
    priority: Int
    text: String!
    text: String
    parent: ID
    children: [ID!]
}

# Define an input type for the mutation below.
# https://graphql.org/learn/schema/#input-types
#
# Note that, this type is mapped to the generated
# input type in mutation_input.go.
input UpdateTodoInput {
    status: Status
    priority: Int
    text: String
    parent: ID
    clearParent: Boolean
    addChildIDs: [ID!]
    removeChildIDs: [ID!]
}

# Define a mutation for creating todos.
# https://graphql.org/learn/queries/#mutations
type Mutation {
    createTodo(input: CreateTodoInput!): Todo!
    updateTodo(id: ID!, input: UpdateTodoInput!): Todo!
    updateTodos(ids: [ID!]!, input: UpdateTodoInput!): [Todo!]!
}
```

We're ready now to run the `gqlgen` code generator and generate resolvers for the new mutations.

```
go generate ./...
```

The result is as follows:

```go
func (r *mutationResolver) CreateTodo(ctx context.Context, input ent.CreateTodoInput) (*ent.Todo, error) {
	panic(fmt.Errorf("not implemented"))
}

func (r *mutationResolver) UpdateTodo(ctx context.Context, id int, input ent.UpdateTodoInput) (*ent.Todo, error) {
	panic(fmt.Errorf("not implemented"))
}

func (r *mutationResolver) UpdateTodos(ctx context.Context, ids []int, input ent.UpdateTodoInput) ([]*ent.Todo, error) {
	panic(fmt.Errorf("not implemented"))
}
```

## Apply Input Types on `ent.Client`

The `Set<F>` calls in the `CreateTodo` resolver are replaced with one call named `SetInput`:

```diff
func (r *mutationResolver) CreateTodo(ctx context.Context, input ent.CreateTodoInput) (*ent.Todo, error) {
	return ent.FromContext(ctx).Todo.
		Create().
-		SetText(todo.Text).
-		SetStatus(todo.Status).
-		SetNillablePriority(todo.Priority). // Set the "priority" field if provided.
-		SetNillableParentID(todo.Parent).   // Set the "parent_id" field if provided.
+		SetInput(input)
		Save(ctx)
}
```

The rest of the resolvers (`UpdateTodo` and `UpdateTodos`) will be implemented as follows:

```diff
func (r *mutationResolver) CreateTodo(ctx context.Context, input ent.CreateTodoInput) (*ent.Todo, error) {
	return ent.FromContext(ctx).Todo.Create().SetInput(input).Save(ctx)
}

func (r *mutationResolver) UpdateTodo(ctx context.Context, id int, input ent.UpdateTodoInput) (*ent.Todo, error) {
-	panic(fmt.Errorf("not implemented"))
+	return ent.FromContext(ctx).Todo.UpdateOneID(id).SetInput(input).Save(ctx)
}

func (r *mutationResolver) UpdateTodos(ctx context.Context, ids []int, input ent.UpdateTodoInput) ([]*ent.Todo, error) {
-	panic(fmt.Errorf("not implemented"))
+	client := ent.FromContext(ctx)
+	if err := client.Todo.Update().Where(todo.IDIn(ids...)).SetInput(input).Exec(ctx); err != nil {
+		return nil, err
+	}
+	return client.Todo.Query().Where(todo.IDIn(ids...)).All(ctx)
}
```

Hurray! We're now ready to test our GraphQL resolvers.

## Test the `CreateTodo` Resolver

Let's start with creating 2 todo items by executing this query with the variables below:

```graphql
mutation CreateTodo($input: CreateTodoInput!) {
   createTodo(input: $input) {
     id
     text
     createdAt
     priority
     parent {
       id
     }
   }
 }
```

#### 1st query variables

```json
{
  "input": {
    "text": "Create GraphQL Example",
    "status": "IN_PROGRESS",
    "priority": 2
  }
}
```

#### Output

```json
{
  "data": {
    "createTodo": {
      "id": "1",
      "text": "Create GraphQL Example",
      "createdAt": "2021-04-19T10:49:52+03:00",
      "priority": 2,
      "parent": null
    }
  }
}
```

#### 2nd query variables

```json
{
  "input": {
    "text": "Create Tracing Example",
    "status": "IN_PROGRESS",
    "priority": 2
  }
}
```

#### Output

```json
{
  "data": {
    "createTodo": {
      "id": "2",
      "text": "Create Tracing Example",
      "createdAt": "2021-04-19T10:50:01+03:00",
      "priority": 2,
      "parent": null
    }
  }
}
```

## Test the `UpdateTodos` Resolver

We continue the example by updating the `priority` of the 2 todo items to `1`.

```graphql
mutation UpdateTodos($ids: [ID!]!, $input: UpdateTodoInput!) {
  updateTodos(ids: $ids, input: $input) {
    id
    text
    createdAt
    priority
    parent {
      id
    }
  }
}
```

#### Query variables

```json
{
  "ids": ["1", "2"],
  "input": {
    "priority": 1
  }
}
```

#### Output

```json
{
  "data": {
    "updateTodos": [
      {
        "id": "1",
        "text": "Create GraphQL Example",
        "createdAt": "2021-04-19T10:49:52+03:00",
        "priority": 1,
        "parent": null
      },
      {
        "id": "2",
        "text": "Create Tracing Example",
        "createdAt": "2021-04-19T10:50:01+03:00",
        "priority": 1,
        "parent": null
      }
    ]
  }
}
```

## Test the `UpdateTodo` Resolver

The only thing left is to test the `UpdateTodo` resolver. Let's use it to update the `parent` of the 2nd todo item to `1`.

```graphql
mutation UpdateTodo($id: ID!, $input: UpdateTodoInput!) {
  updateTodo(id: $id, input: $input) {
    id
    text
    createdAt
    priority
    parent {
      id
      text
    }
  }
}
```

#### Query variables

```json
{
  "id": "2",
  "input": {
    "parent": 1
  }
}
```

#### Output

```json
{
  "data": {
    "updateTodo": {
      "id": "2",
      "text": "Create Tracing Example",
      "createdAt": "2021-04-19T10:50:01+03:00",
      "priority": 1,
      "parent": {
        "id": "1",
        "text": "Create GraphQL Example"
      }
    }
  }
}
```
