Django で GraphQL 実装してみた  Mutation編

## Django で GraphQL 実装してみた
- [環境構築編](https://qiita.com/dbxkazuxdb/items/77a9c6d809a1c706e2db)
- [Query編](https://qiita.com/dbxkazuxdb/items/b1bdc9eac9856deb493c)
- Mutation編 ← この記事  
- [リファクタ編](https://qiita.com/dbxkazuxdb/items/b356912e1968fa8d02bb)

## 実装

### createメソッド追加
app/schema.py
```diff_python
class IngredientNode(DjangoObjectType):
    class Meta:
        model = Ingredient
        interfaces = (relay.Node,)
        filter_fields = {
            "name": ["exact", "icontains", "istartswith"],
            "notes": ["exact", "icontains"],
            "category": ["exact"],
            "category__name": ["exact"],
            "category__is_active": ["exact"],
        }

        
+ class CreateIngredient(Mutation):
+    class Arguments:
+        name = graphene.String(required=True)
+        category_id = graphene.ID(required=True)
+
+   ingredient = graphene.Field(IngredientNode)
+
+    def mutate(self, info, **input):
+        ingredient = Ingredient(
+            name=input["name"],
+            category_id=input["category_id"],
+        )
+        ingredient.save()
+        return CreateIngredient(ingredient=ingredient)    


class Query:
    category = relay.Node.Field(CategoryNode)
    categories = DjangoFilterConnectionField(CategoryNode)

    ingredient = relay.Node.Field(IngredientNode)
    ingredients = DjangoFilterConnectionField(IngredientNode)

    
+ class Mutation:
+     create_ingredient = CreateIngredient.Field()

```

### create mutation実行
createIngredientの中に、queryで取得したい値を指定することができる。
```graphql
mutation{
  createIngredient(name:"new item name", categoryId:"1"){
    ingredient{
      id
      name
      category {
        id
        name
      }
    }
  }
}
```

### relayのIDを解決する
idは、base64エンコードされるため、DBに保存する際は本来の値を保存したい。
from_global_idメソッドを使用する。
戻り値は(type, id)
typeは、DjangoObjectTypeのクラス名、idはDBの値
※今回の場合、typeは`IngredientNode`となる

https://docs.graphene-python.org/en/latest/relay/nodes/#quick-example

app/schema.py
```diff_python
+ from graphql_relay import from_global_id

...

class CreateIngredient(Mutation):
    class Arguments:
        name = graphene.String(required=True)
        category_id = graphene.ID(required=True)

    ingredient = graphene.Field(IngredientNode)

    def mutate(self, info, **input):
+       category_node = from_global_id(input["category_id"])
        ingredient = Ingredient(
            name=input["name"],
-           category_id=input["category_id"],
+           category_id=category_node.id,
        )
        ingredient.save()
        return CreateIngredient(ingredient=ingredient)

```

### updateメソッド追加
app/schema.py
```diff_python
class CreateIngredient(Mutation):
    class Arguments:
        name = graphene.String(required=True)
        category_id = graphene.ID(required=True)

    ingredient = graphene.Field(IngredientNode)

    def mutate(self, info, **input):
        ingredient = Ingredient(
            name=input["name"],
            category_id=input["category_id"],
        )
        ingredient.save()
        return CreateIngredient(ingredient=ingredient)


+ class UpdateIngredient(Mutation):
+     class Arguments:
+         id = graphene.ID(required=True)
+         name = graphene.String()
+         category_id = graphene.String()
+
+     ingredient = graphene.Field(IngredientNode)
+
+     def mutate(self, info, **input):
+         ingredient = Ingredient.objects.get(
+             pk=from_global_id(input["id"]).id,
+         )
+         if input["name"]:
+             ingredient.name = input["name"]
+         if input["category_id"]:
+             node = from_global_id(input["category_id"])
+             ingredient.category_id = node.id
+             
+         ingredient.save()
+         return UpdateIngredient(ingredient=ingredient)



class Query:
    category = relay.Node.Field(CategoryNode)
    categories = DjangoFilterConnectionField(CategoryNode)

    ingredient = relay.Node.Field(IngredientNode)
    ingredients = DjangoFilterConnectionField(IngredientNode)

    
class Mutation:
    create_ingredient = CreateIngredient.Field()
+   update_ingredient = UpdateIngredient.Field()

```
### update mutation実行
```graphql
mutation {
  updateIngredient(id:"SW5ncmVkaWVudE5vZGU6MQ==", name:"update", categoryId:"Q2F0ZWdvcnlOb2RlOjE="){
    ingredient {
      id
      name
      category {
        id
        name
      }
    }
  }
}
```

次は、[リファクタ編](https://qiita.com/dbxkazuxdb/items/b356912e1968fa8d02bb)