SQLAlchemy + Flask Tutorial¶
Graphene comes with builtin support to SQLAlchemy, which makes quite easy to operate with your current models.
Note: The code in this tutorial is pulled from the Flask SQLAlchemy example app.
Setup the Project¶
We will setup the project, execute the following:
# Create the project directory
mkdir flask_sqlalchemy
cd flask_sqlalchemy
# Create a virtualenv to isolate our package dependencies locally
virtualenv env
source env/bin/activate # On Windows use `env\Scripts\activate`
# SQLAlchemy and Graphene with SQLAlchemy support
pip install SQLAlchemy
pip install graphene_sqlalchemy
# Install Flask and GraphQL Flask for exposing the schema through HTTP
pip install Flask
pip install Flask-GraphQL
Defining our models¶
Let’s get started with these models:
# flask_sqlalchemy/models.py
from sqlalchemy import *
from sqlalchemy.orm import (scoped_session, sessionmaker, relationship,
backref)
from sqlalchemy.ext.declarative import declarative_base
engine = create_engine('sqlite:///database.sqlite3', convert_unicode=True)
db_session = scoped_session(sessionmaker(autocommit=False,
autoflush=False,
bind=engine))
Base = declarative_base()
# We will need this for querying
Base.query = db_session.query_property()
class Department(Base):
__tablename__ = 'department'
id = Column(Integer, primary_key=True)
name = Column(String)
class Employee(Base):
__tablename__ = 'employee'
id = Column(Integer, primary_key=True)
name = Column(String)
hired_on = Column(DateTime, default=func.now())
department_id = Column(Integer, ForeignKey('department.id'))
department = relationship(
Department,
backref=backref('employees',
uselist=True,
cascade='delete,all'))
Schema¶
GraphQL presents your objects to the world as a graph structure rather than a more hierarchical structure to which you may be accustomed. In order to create this representation, Graphene needs to know about each type of object which will appear in the graph.
This graph also has a root type through which all access begins. This
is the Query
class below. In this example, we provide the ability to
list all employees via all_employees
, and the ability to obtain a
specific node via node
.
Create flask_sqlalchemy/schema.py
and type the following:
# flask_sqlalchemy/schema.py
import graphene
from graphene import relay
from graphene_sqlalchemy import SQLAlchemyObjectType, SQLAlchemyConnectionField
from .models import db_session, Department as DepartmentModel, Employee as EmployeeModel
class Department(SQLAlchemyObjectType):
class Meta:
model = DepartmentModel
interfaces = (relay.Node, )
class Employee(SQLAlchemyObjectType):
class Meta:
model = EmployeeModel
interfaces = (relay.Node, )
class Query(graphene.ObjectType):
node = relay.Node.Field()
# Allows sorting over multiple columns, by default over the primary key
all_employees = SQLAlchemyConnectionField(Employee.connection)
# Disable sorting over this field
all_departments = SQLAlchemyConnectionField(Department.connection, sort=None)
schema = graphene.Schema(query=Query)
Creating GraphQL and GraphiQL views in Flask¶
Unlike a RESTful API, there is only a single URL from which GraphQL is accessed.
We are going to use Flask to create a server that expose the GraphQL
schema under /graphql
and a interface for querying it easily:
GraphiQL (also under /graphql
when accessed by a browser).
Fortunately for us, the library Flask-GraphQL
that we previously
installed makes this task quite easy.
# flask_sqlalchemy/app.py
from flask import Flask
from flask_graphql import GraphQLView
from .models import db_session
from .schema import schema, Department
app = Flask(__name__)
app.debug = True
app.add_url_rule(
'/graphql',
view_func=GraphQLView.as_view(
'graphql',
schema=schema,
graphiql=True # for having the GraphiQL interface
)
)
@app.teardown_appcontext
def shutdown_session(exception=None):
db_session.remove()
if __name__ == '__main__':
app.run()
Creating some data¶
$ python
>>> from .models import engine, db_session, Base, Department, Employee
>>> Base.metadata.create_all(bind=engine)
>>> # Fill the tables with some data
>>> engineering = Department(name='Engineering')
>>> db_session.add(engineering)
>>> hr = Department(name='Human Resources')
>>> db_session.add(hr)
>>> peter = Employee(name='Peter', department=engineering)
>>> db_session.add(peter)
>>> roy = Employee(name='Roy', department=engineering)
>>> db_session.add(roy)
>>> tracy = Employee(name='Tracy', department=hr)
>>> db_session.add(tracy)
>>> db_session.commit()
Testing our GraphQL schema¶
We’re now ready to test the API we’ve built. Let’s fire up the server from the command line.
$ python ./app.py
* Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
Go to localhost:5000/graphql and type your first query!
{
allEmployees {
edges {
node {
id
name
department {
name
}
}
}
}
}