28
21

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

GraphQLAdvent Calendar 2018

Day 11

Graphene Python による GraphQL × Flask × SQLAlchemy Server の構築

Last updated at Posted at 2018-12-10

本記事の内容

  • この記事では、Graphene Python を利用した GraphQL × Flask × SQLAlchemy Server の構築方法をまとめたものとなっております

GraphQL とは(一応)

  • Facebook製 オープンソースのクエリ言語
  • RESTに変わるものとして注目されている
  • クライアントとサーバ間のデータのやりとりを容易に記述することができる
  • クエリに対して、JSON で結果を返す

参考

Graphene とは

実行環境

  • MacOS Mojave 10.14.1
  • Python 3.6.5
  • Flask 1.0.2
  • sqlite 3.24.0

動かすまで

shellscript

## プロジェクト用のディレクトリを作成
mkdir flask_sqlalchemy
cd flask_sqlalchemy

## virtualenv 環境の作成と読み込み
virtualenv env
source env/bin/activate  # On Windows use `env\Scripts\activate`

## SQLAlchemy と graphene_sqlalchemy の pip install
pip install SQLAlchemy
pip install graphene_sqlalchemy

## Flask と Flask-GraphQL のインストール
pip install Flask
pip install Flask-GraphQL

モデルの定義

flask_sqlalchemy/models.py
# 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'))

スキーマの作成

GraphQLは、慣れ親しんだより階層的な構造ではなく、グラフ構造としてオブジェクトを表現します。

今回の例では、 all_employees を介してすべての従業員を一覧表示する機能と、ノード経由で特定のノードを取得する機能を提供します。

flask_sqlalchemy/schema.py を作成して、次のように編集しましょう。

flask_sqlalchemy/schema.py
# 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 DepartmentConnection(relay.Connection):
    class Meta:
        node = Department


class Employee(SQLAlchemyObjectType):
    class Meta:
        model = EmployeeModel
        interfaces = (relay.Node, )


class EmployeeConnection(relay.Connection):
    class Meta:
        node = Employee


class Query(graphene.ObjectType):
    node = relay.Node.Field()
    # Allows sorting over multiple columns, by default over the primary key
    all_employees = SQLAlchemyConnectionField(EmployeeConnection)
    # Disable sorting over this field
    all_departments = SQLAlchemyConnectionField(DepartmentConnection, sort=None)

schema = graphene.Schema(query=Query)

Flask 上での GraphQL環境を作成

RESTful APIとは異なり、GraphQLにアクセスするURLは1つだけです。

Flaskを使用して、 /graphql の下にGraphQLスキーマを公開するサーバーと、簡単にクエリを実行するための GraphiQL と呼ばれるインターフェイスを作成します。

Flask-GraphQL ライブラリは、この機能を実現できるようサポートしてくれます。

flask_sqlalchemy/app.py
# 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()

データを試しに作成してみる

$ python3 でコンソールを開きます。

>>> 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()

GraphQL の動作テスト

これで、準備は整いました。コマンドラインから Server を起動して動作を確認してみましょう。

$ python3 ./app.py
 * Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)

起動させたら、 http://localhost:5000/graphql にアクセスしてみましょう。

image.png

左側に Query を入力して動作を確かめる。

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

image.png

これでクエリに対するレスポンスを確認できましたね。

本記事の内容は以上となります。
シンプルな GraphQL + DB Server を構築したい時に非常に便利そうです。

うまく動かない方は、Github Repository に example があるのでそちらを試してみてください。

長くなりましたが、読んでいただきありがとうございました❗️

おまけ

MongoDB 用のチュートリアルもあるようです

28
21
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
28
21

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?