GraphQL and Python Series (Expressive Introduction) 
Tags: graphql, python
Published: 2020-06-28 22:30:27

# GraphQL and Python Series (Expressive Introduction)

This is part 1 of an ongoing series to introduce you to using GraphQL and Python. Hopefully, at the end of this series, you will be able to build a GraphQL Backend with Django and Graphene.

## GraphQL Introductions

GraphQL is a strongly typed language and is an alternative to REpresentational Transfer(REST).
>Missing explanation: Try and explain why GraphQL was created and why it's an alternative to REST. PayPal Engineering Medium article can help.
An example of a GraphQL query us as follows:

```GraphQL
{
    allFilms {
        films {
            title
    }
  }
}
```

### GraphQL Type Schema

We'd mostly be using two types in GraphQL, the Object Type and the Scalar Type.
Object types can contain their own set of subfields, generally speaking, they have to be an object.

Scalar types are built-in GraphQL data types, and they are five in number: integers, floats, strings, booleans and ids(these are unique strings). Now, these are the standard five, but they can be extended and still be Scalar Types as we will in this article.

### CRUD Operations in GraphQL

Create Read Update Delete(CRUD) functionalities are done in GraphQL using two operations: Query and Mutations. Just like we've done above, reading data(R) is done normally using queries. But to write or change data, we need a GraphQL operation called Mutation.
In summary, CUD - is covered by mutations while R - is covered by queries. The codes below are examples of using mutation to create, update and delete objects respectively

```GraphQL
mutation {
    createBaby(bodyInfo: {
        name:"Edidiong",
        votes: 1
  })  {
      name
      votes
  }
}

mutation {
    upvote(name: "Edidiong") {
        name
        votes
    }
}

mutation {
    remove(name: "Edidiong") {
        name
        votes
    }
}
```

You notice when reading data, you don't need to use query keyword but in creating, updating or deleting data, you use the mutation keyword so the engine knows you're doing a mutation.

## Intro to Graphene/GraphQL In Python

By now you have seen how to do queries and mutations in Vanilla GraphQL(borrowing the word Vanilla from JavaScript), let's see how to perform GraphQL in Python.

### Query Operation

To create a query, you, first of all, need a root query(this point will be explained in the code session below). Also, GraphQL uses the OOP structure to work so if you're not familiar with OOP, you may find it difficult to follow.

#### Code

Create a new file called `schema.py` and rewrite these codes here into the file.

```Python
import uuid
import json
from datetime import datetime
import graphene

class User(graphene.ObjectType):
    id = graphene.ID(default_value=str(uuid.uuid4()))
    username = graphene.String()
    created_at = graphene.DateTime(default_value=datetime.now())


class Query(graphene.ObjectType):
    users = graphene.List(User, limit=graphene.Int())
    hello = graphene.String()

    def resolve_hello(self, info):
        return "world"

    def resolve_users(self, info, limit=None):
        return [
            User(id="1", username="Khalid", created_at=datetime.now()),
            User(id="2", username="Ann", created_at=datetime.now()),
            User(id="3", username="fred", created_at=datetime.now()),
            ][:limit]


# Query of users
schema = graphene.Schema(query=Query, auto_camelcase=True)
result = schema.execute(
    '''
    {
        users {
            id
            username
            createdAt
        }
    }
    '''
)
dict_result = dict(result.data.items())
print(dict_result)
```

Let's break down the code above to grasp what was done.

#### User

A `User` class was created that inherited from the `graphene.ObjectType`. Almost all of the GraphQL types you define will be object types(only a few percentages will be Scalar Types). Object types have a name, but most importantly describe their fields.

So the `User` class contains the id, username and date the account was created all. You  will notice id and username are default scalar types(the `.ID()` and `.String()`), we are adding `.DateTime()` as a scalar type(Dive deep into the Graphene source code to see all available Scalar types).

#### Query

Earlier, we learnt that to create a query in graphene, we first need a root query. The class `Query` is that root query. We have two class attributes defined in the query: `hello` and `users`. More about the `hello` query later.
The `users` attribute takes in the `User` class and a `limit` argument, these two are what we would use in our actual GraphQL query. The users' details will be returned in a `List` structure.

The methods we have created in this `Query` class are called `resolvers`. Resolvers are functions that resolves a value for a type or field in a schema. Simply put, resolvers are what return objects or scalar from our query. To name a resolver, it has to have the word `resolve_` in its name(just like how [Test Driven Development in Python](https://github.com/edeediong/Articles/blob/master/Embracing%20Pytest.md)) are. We also set a default value for the limit parameter.

#### Schema

To execute the code we've written, we will use the Graphene `Schema`. The graphene schema can execute operations(query, mutation and subscription) against the defined types. Looking up type definitions and answering questions about the types through introspection are advance use cases of the schema.
The schema has a `query` parameter which we will pass our class `Query` into as an argument. This query argument is the entry point for fields to **read** data in our Schema.

#### Execute

To provide the result, we use the `execute` method in the Schema class. In this method, we will provide the query in a GraphQL format but since we're using Python, it will be wrapped in a Block comment. In GraphQL, it is standard to use camelCase names. So our Fieldnames are transformed in Schema's TypeMap from snake_case to camelCase and this is made possible because of the `auto_camelcase` argument and it set to `True` by default.
The effect is seen in our query as `created_at` is changed to `createdAt` following the `camelCase` convention.

#### Result

You should have a response like the image below
>**Include The Result Image.**

To better format the result, we use the `json.dumps` method so as to use the `indent` parameter in this method. Alter the print statement above to the one below and run it to see the newly formatted result.

```Python
print(json.dumps(dict_result, indent=2))
```

>**Include The Result Image.**
If you have a result similar to the image above, congratulations.

The limit parameter is by default set to `None` so the output shows all the users in the resolver. If we set a limit to 1 as we do in the code below, we see it returns just a single query.

```Python
result = schema.execute(
    '''
    {
        users(limit: 1) {
            id
            username
            createdAt
        }
    }
    '''
)
```

>**Note:** The `(limit: 1)` is used because of the `users` attribute in the class `Query`. We had defined `limit` as a scalar type inside the users: which is what made `(limit: 1)` work.

Also, we created a hello resolver. We will say this is our hello world in Graphene. To run the hello query, replace the previous query with the one below:

```GraphQL
{
    hello
}
```

>**Include The Result Image.**
The image above is a result of the query.

We have been able to understand everything there is about queries. Now let's move to mutations.

### Mutation Operations

Remember when we said to create queries we need a root query, in mutations, it's sorta different. The Mutation is a convenience type that helps us build a `Field` which takes `Arguments` and returns a `mutation Output ObjectType`. This means to perform CUD operations, we need to pass arguments to a mutation. To pass in arguments to a mutation we need to pass in an inner Arguments class.

#### Code(mutation)

Add these new classes into the `schema.py` file but arrange the classes to be on top of another.

```Python
class CreateUser(graphene.Mutation):
    user = graphene.Field(User)

    class Arguments:
        username = graphene.String()


    def mutate(self, info, username):
        user = User(id="4", username=username, created_at=datetime.now())
        return CreateUser(user=user)


class Mutation(graphene.ObjectType):
    create_user = CreateUser.Field()
```

Also, comment out the previous schema and append this to the end of the file.

```Python
# Mutation
schema = graphene.Schema(query=Query, mutation=Mutation)
result = schema.execute(
    '''
    mutation {
        createUser(username: "Edidiong") {
            user {
                id
                username
                createdAt
            }
        }
    }
    '''
)
```

Let's break down the code above to grasp what was done.

#### CreateUser

The `CreateUser` class inherits from graphene's `Mutation` class and creates a Field that is available on an ObjectType. The ObjectType here is our `User` class.

#### Arguments

`Arguments` inner class passes the attribute `username` to the `CreateUser` class and this username is gotten from the resolver. This attribute is a Scalar Type(String) and it's the arguments we use for the mutation Field.

The `mutate` method is a resolver method for the Mutation class. It performs data change and returns the output which in this case the `username`, `id` and `created_at` are the data change and a new user is returned.

#### Mutation

The Mutation class takes in the `CreateUser` class and mounts it as a `Field`. Like we know, almost all GraphQL types you define will be `ObjectType`. Refer to the Mutation Operation header to understand what happens behind the engine of the `Mutation` class.

#### Schema(mutation)

We already know about the Schema class and `query` parameter. The `mutation` parameter describes the entry point for fields to *create, update or delete* data in our API. We pass in the `Mutation` class as an argument to the `mutation` argument so as to perform CUD operations with it(in our case it's only Create we've done).

#### Execute(mutation)

The execute in mutation also does the same thing as execute in query: to read the query from a GraphQL format into a Python format so as a result can be gotten.
The only difference is the way to write the call. The `mutation` keyword comes in just like we were told earlier in the article. From the previous Execute header, we understand how `(username: "Edidiong")` comes about.

#### Result

We should have a result similar to the image below.
>**Include The Result Image.**

### Subscription Operations

## Next Steps

Next, we will talk about Building GraphQL Backends with Django and Graphene. If you liked the article upvote and either drop a comment below or send me a [mail](edeediong@gmail.com)