GraphQL Simplistic CRUD

Sarit Ritwirune
2 min readNov 22, 2019

--

This is my first time playing with GraphQL, but it is not my first time developing Django CRUD API endpoint. I have done with Django REST Framework(DRF) for several projects. My seniors guided me very well

The goals of this article are CRUD on one single model instance. I know they are 3 approaches that GraphQL can do with mutations(ModelForm, ModelSerializer, and Relay)

And to delete the instance you have to customize you own way

Let’s get started from naive approach with single model single endpoint not use any filter yet to keep my article short

First one model and serializer I would like to follow DRF approach because it is not only do a validation like `ModelForm`, but also support nested payload

from graphene_django import DjangoObjectType
from rest_framework import serializers
class Question(models.Model):
question_text = models.CharField(max_length=50)
class QuestionSerializer(serializers.ModelSerializer):
class Meta:
model = Question
fields = (
'id',
'question_text',
)
class QuestionType(DjangoObjectType): class Meta:
model = Question
fields = (
'id',
'question_text',
'category',
)

Mutation POST/UDATE/DELETE

I have to customize my own DELETE
`ok` field might now make any sense for you, but you will see it in action soon

class DeleteQuestion(graphene.Mutation):
ok = graphene.Boolean()

class Arguments:
id = graphene.ID()

@classmethod
def mutate(cls, root, info, **kwargs):
obj = Question.objects.get(id=kwargs.get('id'))
obj.delete()
return cls(ok=True)
class QuestionSerializerMutation(SerializerMutation):
delete_question = DeleteQuestion.Field()

class Meta:
serializer_class = QuestionSerializer
model_operation = ['crated', 'update']
lookup_field = 'id'

And Mutation class with remarkable name

class Mutation(graphene.ObjectType):
xxx = QuestionSerializerMutation.Field()
class QPQuery(graphene.ObjectType):
questions = graphene.List(QuestionType)
question = graphene.Field(QuestionType,
question_id=graphene.String(),
bar=graphene.Int())
def resolve_questions(self, info, **kwargs):
return Question.objects.all()

def resolve_question(self, info, question_id, bar):
print(bar)
return Question.objects.get(pk=question_id)

And schema

schema = graphene.Schema(query=QPQuery, mutation=Mutation)

Analogy with traditional HTTP method

GET List

query{
questions{
id
questionText
}
}

Response. Almost good I will cover the filter, pagination and authentication later day

{
"data": {
"questions": [
{
"id": "5",
"questionText": "qKRDzeRqFapnNGuvhGVdmdDZJCUBPUpwaTNgNJDKzpTAnuklmk"
},
{
"id": "6",
"questionText": "WLYiBpnZPpJdGstouKzGgSnLfMsGiXaRWqKJMQCVKMIucAZQJc"
},
{
"id": "8",
"questionText": "Batman"
}
]
}
}

GET Detail

{
"data": {
"question": {
"id": "8",
"questionText": "Batman"
}
}
}

POST Create

mutation{
xxx(input: {questionText: "How to get rich?"}){
id
questionText
errors{
field
messages
}
}
}

In order to get the error messages you have to add errors

PATCH/PUT Update

mutation{
xxx(input: {id: 8, questionText: "How to heal my burn wound?"}){
id
questionText
}
}

DELETE

It seems redundant here because I have to fill in input 2 times. I will optimize my endpoint in later time

mutation{
xxx(input: {id: 10, questionText: ""}){
deleteQuestion(id:10){
ok
}
}
}

GraphQL is good, but document is not mature yet. I spent my time 3 hours to figure out the endpoint which is OK for me. Hope tooling engineer will supply more recipe on this great tool.

--

--

Sarit Ritwirune

On the way to full stack cross-platform. Currently make living by data science.