tutorial.rst @28ad7809-2494-431f-8afc-48988c7574fe/upstream — view markup · raw · history · blame
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 } } } } }