DEV Community

Sadhan Sarker
Sadhan Sarker

Posted on

Python Flask GraphQL with Graphene

Python Flask GraphQL with Graphene

GraphQL is a query language for APIs. It's becoming more popular because of the many benefits it offers compared to REST APIs, of which the most important one is smarter data fetching.
The querying model offered by GraphQL is showing its real power when it comes to working with large APIs. It's basically API specification or protocol which provides more efficient, powerful and
alternative to REST. It developed by open-source Facebook and now it's maintained by a large community of companies and individuals from all over the world.

As nowadays declarative programming is becoming popular day by day. It's sound good cause GraphQL also enables declarative data fetching. Instead of multiple rest API calling increases
roundtrips, GraphQL server only exposes a single endpoint and responds with precisely the data a client asked for. we will look it with example.

GraphQL vs REST

  • GraphQL allows us to specify what data we need in a query and that's what's going to be included in a response – nothing more, nothing less, just the data we asked for in a single request. On the other hand, when fetching for the same data with REST we would end up with multiple REST roundtrips ...

Let's deep drive into GraphQL vs REST with an example:

To illustrate the major differences between REST and GraphQL when it comes to fetching data from an API,

  • let’s consider a simple example scenario: In a blogging application, an app needs to display the titles of the posts of a specific user.
  • The same screen also displays the names of the last 3 followers of that user. How would that situation be solved with REST and GraphQL?

Python Flask GraphQL with Graphene

GraphQL is a query language for APIs. It's becoming more popular because of the many benefits it offers compared to REST APIs, of which the most important one is smarter data fetching.
The querying model offered by GraphQL is showing its real power when it comes to working with large APIs. It's basically API specification or protocol which provides more efficient, powerful and
alternative to REST. It developed by open-source Facebook and now it's maintained by a large community of companies and individuals from all over the world.

As nowadays declarative programming is becoming popular day by day. It's sound good cause GraphQL also enables declarative data fetching. Instead of multiple rest API calling increases
roundtrips, GraphQL server only exposes a single endpoint and responds with precisely the data a client asked for. we will look it with example.

GraphQL vs REST

  • GraphQL allows us to specify what data we need in a query and that's what's going to be included in a response – nothing more, nothing less, just the data we asked for in a single request. On the other hand, when fetching for the same data with REST we would end up with multiple REST roundtrips ...

Let's deep drive into GraphQL vs REST with an example:

To illustrate the major differences between REST and GraphQL when it comes to fetching data from an API,

  • let’s consider a simple example scenario: In a blogging application, an app needs to display the titles of the posts of a specific user.
  • The same screen also displays the names of the last 3 followers of that user. How would that situation be solved with REST and GraphQL?

Solution with a REST API:

In REST we fetch data through multiple endpoints.

  • In the example, these could be /users/<id> endpoint to fetch the initial user data.
  • Secondly, there’s likely to be a /users/<id>/posts endpoint that returns all the posts for a user.
  • Finally, The third endpoint will then be the /users/<id>/followers that returns a list of followers per user.


Source: howtographql.com

Note: Using REST, we have to make different three requests to fetch data, We're also overfetching additional information that's not needed.

On the other hand, we can create single REST endpoint which serves our desire data like /users/posts/followers/<id> that save networking roundtrips, It's okay
But it will be horrible. when we try to change additional filters attributes ex. date or more /users/posts/followers/<id>/<date>.
See our API URLs are increasing, which is hard for maintains and tracks.

Solution with GraphQL API:

In GraphQL simply send a single query to the GraphQL server. The server then responds with a JSON data


Source: howtographql.com

Note: Using GraphQL, the client can specify exactly the data it needs in a query. Notice that the structure of the server’s response follows precisely the nested structure defined in the query.

Isn't it cool staff ?. It's enough about theory. Let's implement GraphQL server using Python Graphene

Implement GraphQL server using Python Graphene

Graphene is basically python GraphQl client library. with the help of that, we can create your GraphQL Server.

Setting up your project

🔰 First, to set up a project create a directory/folder like below

$ mkdir graphql-flask
$ cd graphql-flask
Enter fullscreen mode Exit fullscreen mode

🔰 It's time to create a virtual environment. So we can avoid conflict, from global packages.
It helps us to manage different packages versions for individual projects. if you don't have a virtual environment then
install it using below command,

$ pip install virtualenv
$ virtualenv venv
$ source venv/bin/activate
Enter fullscreen mode Exit fullscreen mode

Install require dependencies, using below command:

$ pip install flask flask-graphql flask-migrate flask-sqlalchemy graphene graphene-sqlalchemy
Enter fullscreen mode Exit fullscreen mode

🔰 Now, we need to initialize our database to do so, We need to create another python script to process easier,

create seed.py file and includes,

from app import db, User, Post

db.create_all()     # create tables from models

user1 = User(
    name="Sadhan Sarker",
    email='cse.sadhan@gmail.com'
)

post1 = Post()
post1.title = "Blog Post Title 1"
post1.body = "This is the first blog post 1"
post1.author = user1

db.session.add(post1)
db.session.add(user1)
db.session.commit()

print(User.query.all())
print(Post.query.all())
Enter fullscreen mode Exit fullscreen mode

We need to run that script from a virtual environment using,

python seed.py
Enter fullscreen mode Exit fullscreen mode

👏 Great! Well, we are doing lots. we are almost closer to end,

🔰 Eventually, create 'app.py' and includes,

import os

import graphene
from flask import Flask
from flask_graphql import GraphQLView
from flask_sqlalchemy import SQLAlchemy
from graphene_sqlalchemy import SQLAlchemyObjectType, SQLAlchemyConnectionField

app = Flask(__name__)

basedir = os.path.abspath(os.path.dirname(__file__))

# Database Configs [Check it base on other Database Configuration]
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///' + os.path.join(basedir, 'database.sqlite')
app.config['SQLALCHEMY_COMMIT_ON_TEARDOWN'] = True
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = True

# Initialize Database
db = SQLAlchemy(app)


# ------------------  Database Models ------------------

class User(db.Model):
    __tablename__ = 'users'
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(256))
    email = db.Column(db.String(256), index=True, unique=True)  # index => should not be duplicate
    posts = db.relationship('Post', backref='author')

    def __repr__(self):
        return '<User %r>' % self.email


class Post(db.Model):
    __tablename__ = 'posts'
    id = db.Column(db.Integer, primary_key=True)
    title = db.Column(db.String(256))
    body = db.Column(db.Text)
    author_id = db.Column(db.Integer, db.ForeignKey('users.id'))

    def __repr__(self):
        return '<Post %r>' % self.title


# ------------------ Graphql Schemas ------------------


# Objects Schema
class PostObject(SQLAlchemyObjectType):
    class Meta:
        model = Post
        interfaces = (graphene.relay.Node,)


class UserObject(SQLAlchemyObjectType):
    class Meta:
        model = User
        interfaces = (graphene.relay.Node,)


class Query(graphene.ObjectType):
    node = graphene.relay.Node.Field()
    all_posts = SQLAlchemyConnectionField(PostObject)
    all_users = SQLAlchemyConnectionField(UserObject)


# noinspection PyTypeChecker
schema_query = graphene.Schema(query=Query)


# Mutation Objects Schema
class CreatePost(graphene.Mutation):
    class Arguments:
        title = graphene.String(required=True)
        body = graphene.String(required=True)
        email = graphene.String(required=True)

    post = graphene.Field(lambda: PostObject)

    def mutate(self, info, title, body, email):
        user = User.query.filter_by(email=email).first()
        post = Post(title=title, body=body)
        if user is not None:
            post.author = user
        db.session.add(post)
        db.session.commit()
        return CreatePost(post=post)


class Mutation(graphene.ObjectType):
    save_post = CreatePost.Field()


# noinspection PyTypeChecker
schema_mutation = graphene.Schema(query=Query, mutation=Mutation)


# Flask Rest & Graphql Routes
@app.route('/')
def hello_world():
    return 'Hello From Graphql Tutorial!'


# /graphql-query
app.add_url_rule('/graphql-query', view_func=GraphQLView.as_view(
    'graphql-query',
    schema=schema_query, graphiql=True
))

# /graphql-mutation
app.add_url_rule('/graphql-mutation', view_func=GraphQLView.as_view(
    'graphql-mutation',
    schema=schema_mutation, graphiql=True
))

if __name__ == '__main__':
    app.run()
Enter fullscreen mode Exit fullscreen mode

✅We made it together, successfully we are able to integrate graphql with graphene. Now' run and test our app.

To Run Application,

$ python app.py
Enter fullscreen mode Exit fullscreen mode

Test GraphQL API'S by following steps

Use any Rest Client like PostMan or cRUL we can use other clients also,

## 1. Rest API examples
GET http://127.0.0.1:5000/

### Graphql query-api example
POST http://127.0.0.1:5000/graphql-query
Content-Type: application/graphql

{
  allPosts{
    edges{
      node{
        title
        author{
          email
        }
      }
    }
  }
}

### 2. Graphql mutation-api example

POST http://127.0.0.1:5000/graphql-mutation
Content-Type: application/graphql

mutation {
  savePost(email:"cse.sadhan@gmail.com", title:"Title 2", body:"Blog post 2") {
    post{
      title
      body
      author{
        email
      }
    }
  }
}

###
Enter fullscreen mode Exit fullscreen mode

👌 Congratulations!. & Thank You!
Feel free to comments, If you have any issues & queries.

References:

Top comments (4)

Collapse
 
azamanaza profile image
Miguel Felipe Calo • Edited

"On the other hand, when fetching for the same data with REST we would end up with multiple REST roundtrips"

IMO, anything graphql does, rest can and vice versa. But when you're doing more REST things on a graphql api, then you should just go REST.

Many rest frameworks support "data" or property filtering.

Collapse
 
khaledbadenjki profile image
Khaled Badenjki

Said every REST developer who is too afraid to jump into the GraphQl world :P

Collapse
 
luturol profile image
Rafael Ahrons

Great Article! GraphQL looks a lot more easier than making a Restful API in flask. I'm currently studying how to build one using Flask and kind end up loving how easy you can build things using Python and Flaks.

There is a duplicated paragraph on your article at the begining

Collapse
 
mesadhan profile image
Sadhan Sarker

Yes! I know that, so I mention links in reference. Don't take it the negative way I'm just learning how to implement it on python flask. And just trying to put everything as a future reference as well as I think it can be helpful for others.

Thanks for your valuable comment.

Some comments may only be visible to logged-in visitors. Sign in to view all comments.