サービスを定義する手段として、REST APIの他、GraphQLがあります。
これは、データベースのデータを操作するためのSQLのように、サーバ内にあるデータを直接的にアクセスするようなインタフェースを定義するものです。
そのため、厳格なインタフェースを定義するAPI(Application Programming Interface)というより、データ操作をするミドルウェアのような使い方を可能とする柔軟性に富んだインタフェースを定義できます。
■ GraphQLの概要
GraphQLの特徴は、原則として、以下で述べたREST APIの特徴と同様です。
異なるのは、REST APIのようにエンドポイントをインタフェース毎に分けるのではなく、GraphQLのエンドポイントだけを作成し、その中でインタフェースを定義するような形をとります。
GraphQLにはインタフェースを定義するための独自の「スキーマ」と呼ばれる言語(SDL)が存在し、それを使ってインタフェースを定義します。そのインタフェース定義を解釈するためのGraphQLのエンジンがあり、そして、その処理を実際に実行するのがリゾルバと呼ばれます。
インタフェースの定義は、以下の2種類に分けられます。
1)クエリ(Query)
参照系のインタフェースの定義。SQLのSELECTほどではないが、条件の指定、結果の中から取得したいデータ項目の指定(カラムの選択)などを定義できる。JSON形式で指定し、結果もJSON形式で返却する。
※クエリに指定した結果の中から取得したいデータ項目をレスポンスから選択する処理は、GraphQLのエンジンで実施される。そのため、リゾルバ側では、結果の中から選択する処理を実装する必要はない。
2)ミューテーション(Mutation)
更新系のインターフェースの定義。追加、更新、削除などのデータを変更するインタフェースを定義できる。JSON形式で指定し、結果もJSON形式で返却する。
■ SDLによるスキーマ定義
SDLのデータ型には、文字列(String)、整数(Int)、浮動小数点(Float)、ブーリアン(Boolean)、ユニーク識別子(ID)があります。これらを組み合わせ、構造体を定義することもできます。
クエリとミューテーションは、これらのデータ型を処理する関数として定義します。
例えば、以下のような定義となります。
// クエリ
type Query {
// hello関数→パラメータ(name:文字列(NULL許容しない))、リターン(文字列)
hello(name:String!): String
}
// ミューテーション
type Mutation {
// hello_add関数→パラメータ(name:文字列(NULL許容しない)、number:整数)、リターン(文字列)
hello_add(name:String!,number:Int!): String
}
//スキーマ定義
schema {
query: Query, //クエリ
mutation: Mutation //ミューテーション
}
■ Python/FlaskによるGraphQLの実装サンプル
準備として、GarphQLのフレームワークとして、Ariadneを使用します。以下のようにインストールします。
pipenv install ariadne
実装の概要を以下に示します。
・クライアントのサンプルソース
# -*- coding: utf-8 -*-
import requests
#
# POST送信(クエリ)
#
# REST APIのURL
url = "http://127.0.0.1:50443/graphql"
# リクエストデータ(JSON)
# query: クエリ
query_data={'query':'query{hello(name:"test")}'}
# POST送信(タイムアウト10秒)
response = requests.post(
url=url,
timeout=10,
json=query_data
)
# レスポンスコードを取得
status_code = response.status_code
# 200 OKの場合、レスポンスデータ(JSON) を取得
if status_code == 200:
res_data = response.json()
print(res_data)
#
# POST送信(ミューテーション)
#
# REST APIのURL
url = "http://127.0.0.1:50443/graphql"
# リクエストデータ(JSON)
# query: ミューテーション
query_data={'query':'mutation{hello_add(name:"test",number:123)}'}
# POST送信(タイムアウト10秒)
response = requests.post(
url=url,
timeout=10,
json=query_data
)
# レスポンスコードを取得
status_code = response.status_code
# 200 OKの場合、レスポンスデータ(JSON) を取得
if status_code == 200:
res_data = response.json()
print(res_data)
・サーバのサンプルソース
# -*- coding: utf-8 -*-
from ariadne import make_executable_schema, gql, QueryType, graphql_sync, MutationType
from ariadne.asgi import GraphQL
from ariadne.explorer import ExplorerGraphiQL
from flask import Flask, request, jsonify
# GraphQLのスキーマ定義文字列(SDL)
type_defs = gql(
"""
type Query {
hello(name:String!): String
}
type Mutation {
hello_add(name:String!,number:Int!): String
}
schema {
query: Query,
mutation: Mutation
}
"""
)
# クエリのインスタンスの生成
query = QueryType()
# クエリのリゾルバを定義
#
# helloという名前のクエリを定義
# 引数:name
# 戻り値:文字列
@query.field("hello")
def resolve_hello(*_,name):
return "Hello world!"+"="+name
# ミューテーションのインスタンスの生成
mutation = MutationType()
# ミューテーションのリゾルバを定義
#
# hello_addという名前のミューテーションを定義
# 引数:name,number
# 戻り値:文字列
@mutation.field("hello_add")
def resolve_hello_add(*_,name,number):
return "Hello world!"+"="+name+","+str(number)
# GraphQLスキーマのインスタンスの作成
schema = make_executable_schema(type_defs, query, mutation)
# Flaskのインスタンスの作成
app = Flask(__name__)
# GETでGraphQL Playgroundの画面を返すエンドポイント
@app.route("/graphql", methods=["GET"])
def graphql_playground():
# Playground accepts GET requests only.
# If you wanted to support POST you'd have to
# change the method to POST and set the content
# type header to application/graphql
explorer_html = ExplorerGraphiQL().html(None)
return explorer_html, 200
# POSTでGraphQLのエンドポイントを返すエンドポイント
@app.route("/graphql", methods=["POST"])
def graphql_server():
# JSONデータを取得
data = request.get_json()
# GraphQLの実行
success, result = graphql_sync(schema, data, context_value={"request": request})
# ステータスコードの設定
status_code = 200 if success else 400
# JSONデータを返す
return jsonify(result), status_code
GraphQLのフレームワークには、テスト用画面があり、上記のサンプルでは、以下のようにGETによって表示することができます。
http://127.0.0.1:50443/graphql
●クエリを実行した結果は、以下となります。
●ミューテーションを実行した結果は、以下となります。
■ まとめ
外部に公開するようなマイクロサービスのAPIとしては、インタフェース定義が規定化できるREST APIの方が適しています。
しかし、Web画面などUIコンポーネントでデータ操作を行う場合では、SQLを直接呼び出すよりも、GraphQLによってマイクロサービス化してAPIを疎結合とするほうが、可用性、拡張性、移植性を確保することができます。
ソフトウェア開発・システム開発業務/セキュリティ関連業務/ネットワーク関連業務/最新技術に関する業務など、「学習力×発想力×達成力×熱意」で技術開発の実現をサポート。お気軽にお問合せ下さい