graphene/docs/pages/docs/sqlalchemy/tutorial.md
2016-02-07 20:18:10 -08:00

5.1 KiB

title description
Tutorial Using SQLAlchemy with Graphene

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.contrib.sqlalchemy import SQLAlchemyNode, SQLAlchemyConnectionField
from models import db_session, Department as DepartmentModel, Employee as EmployeeModel

schema = graphene.Schema()


@schema.register
class Department(SQLAlchemyNode):
    class Meta:
        model = DepartmentModel


@schema.register
class Employee(SQLAlchemyNode):
    class Meta:
        model = EmployeeModel


class Query(graphene.ObjectType):
    node = relay.NodeField()
    all_employees = SQLAlchemyConnectionField(Employee)

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 under /graphiql.

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 GraphQL

from models import db_session
from schema import schema, Department

app = Flask(__name__)
app.debug = True

# This is creating the `/graphql` and `/graphiql` endpoints
GraphQL(app, schema=schema)

@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/graphiql and type your first query!

{
  allEmployees {
    edges {
      node {
        id
        name
        department {
          name
        }
      }
    }
  }
}