以无服务器方式使用GraphQL(Python + Graphene + DynamoDB + Zappa)
该文章是2017年Serverless Advent Calendar第21天的文章。
据说AppSync的预览申请正在迅速通过。
我在发布后立即申请了,本来想等到写这篇文章时申请通过就尝试使用AppSync进行一些尝试,但是到现在还没有通过,所以我灰心了,就尝试了这样的事情。
当我在谷歌上搜索时,常常能够找到使用Node.js实现无服务器GraphQL的案例,但却找不到Python的案例,所以我尝试着实现了一下。
鉴于我对GraphQL技术还在学习阶段,所以不会进行解释。这里仅说明:嗨,它已经运行啦!
我想做的事情
客户端
↓ ↑(GraphQL)
API 网关
↓ ↑
Lambda(Python3)
↓ ↑
DynamoDB
环境
$ python --version
Python 3.6.1
$ pip --version
pip 9.0.1
使用的框架模块
石墨烯
GraphQL的框架。
PynamoDB
这个工具可以让Python开发者轻松地使用DynamoDB。
graphql-pynamodb是一个用于在Python中连接GraphQL和PynamoDB的库。
使用Flask + Graphene + PynamoDB实现集成。
扎帕
无服务器框架。可以将使用Flask编写的应用程序部署为无服务器应用程序。它将为您部署API Gateway和Lambda。
使用样本
在 graphql-pynamodb 中包含有一个 Flask 应用程序的示例,使用它可以构建一个可以通过 GraphQL 查询 DynamoDB 数据的 Flask 应用程序。(稍微进行了一些修改,稍后会进行说明。)
选择Zappa作为无服务器框架的原因是因为这个原因。如果使用Zappa直接部署这个Flask应用,可以简单地实现无服务器化。
备 **************************************************************************
$ git clone https://github.com/yfilali/graphql-pynamodb.git
$ cd graphql-pynamodb/examples/flask_pynamodb
$ virtualenv env
$ source env/bin/activate
$ pip install -r requirements.txt
到目前为止,按照README中的步骤进行操作。
因为requirements.txt中列出的模块版本过旧,导致出现错误,所以需要安装最新版本。
$ pip install graphene-pynamodb==1.0.0 graphene==2.0
我已经更改了 graphene 和 graphene-pynamodb 的版本。
接下来我们将修改models.py文件。
在这里我们定义了DynamoDB的键名和数据类型等信息。由于这个示例看起来是在访问本地数据库,所以我们注释掉这部分代码,并指定区域。请在所有类中进行如下修改。
# host = "http://localhost:8000"
region = 'ap-northeast-1'
接下来我们要修改 database.py。
在 app.py 中启动应用程序时,这个脚本用于初始化数据库。但是由于不能成功创建 DynamoDB,或者每次启动都会添加数据,造成一些不便。所以我们对其进行了修正。
from uuid import uuid4
def init_db():
# import all modules here that might define models so that
# they will be registered properly on the metadata. Otherwise
# you will have to import them first before calling init_db()
from models import Department, Employee, Role
if not Department.exists():
Department.create_table(read_capacity_units=1, write_capacity_units=1, wait=True)
engineering = Department(id=str(uuid4()), name='Engineering')
engineering.save()
hr = Department(id=str(uuid4()), name='Human Resources')
hr.save()
if not Role.exists():
Role.create_table(read_capacity_units=1, write_capacity_units=1, wait=True)
manager = Role(id=str(uuid4()), name='manager')
manager.save()
engineer = Role(id=str(uuid4()), name='engineer')
engineer.save()
if not Employee.exists():
Employee.create_table(read_capacity_units=1, write_capacity_units=1, wait=True)
peter = Employee(id=str(uuid4()), name='Peter', department=engineering, role=engineer)
peter.save()
roy = Employee(id=str(uuid4()), name='Roy', department=engineering, role=engineer)
roy.save()
tracy = Employee(id=str(uuid4()), name='Tracy', department=hr, role=manager)
tracy.save()
只需要一种选项:
如果在应用程序启动时DynamoDB不存在,则创建它并填充示例数据。 schema.py和app.py保持不变就可以。
本地代码运行
我先在本地进行测试来看看是否可以运行。
$ python app.py
* Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
* Restarting with stat
* Debugger is active!
* Debugger PIN: 287-543-857
由于在首次启动时需要创建DynamoDB表,因此启动过程可能需要一些时间。
起动后,尝试访问 http://127.0.0.1:5000/graphql。这样你就可以通过一个名为GraphiQL的GUI界面来进行查询操作的控制台了。
因此,我們將嘗試以這種方式發出查詢請求。
{
allEmployees {
edges {
node {
id,
name,
department {
id,
name
},
role {
id,
name
}
}
}
}
}
我成功地查询了DynamoDB中的所有数据。如果尝试删除id和name等字段,我认为只能获取到查询语句中提及的内容。
无服务器化
现在本地正在运行Flask服务器,我将尝试用Zappa进行部署并实现无服务器化。
$ pip install zappa
$ zappa init
虽然有很多问题,但如果在凭据配置文件中使用默认设置,默认情况下都可以直接按回车键,应该不会有问题。
部署
确认 zappa_settings.json 已经创建完成后,进行部署。
$ zappa deploy
・・・
Deployment complete!: https://xxxxxxxxxx.execute-api.ap-northeast-1.amazonaws.com/dev
生成的端点+/graphql将变成GraphQL端点。
确认
为了确认,我会通过Chrome扩展等途径进行查询。
我使用chromeiql。当我下载并打开Chrome后,会出现一个名为“Set endpoint”的文本框,我在那里输入GraphQL的端点。
端点看起来是这样的。
https://xxxxxxxxxx.execute-api.ap-northeast-1.amazonaws.com/dev/graphql
当设置终点时,将显示GraphiQL控制台界面,与之前相同。
当你在左边位置输入之前在本地确认过的查询并运行,我想你会得到类似的结果。
留心
当我在本地测试时,我会在Flask启动时检查是否存在DynamoDB表,如果不存在,就创建一个。然而,在转为无服务器后,它不会处理这个步骤,所以如果表不存在,就需要自己创建。由于我将本地创建的表从无服务器应用程序中重新使用,所以我认为这没有问题。
资源删除使用 $ zappa undeploy。
总结
用Zappa可以将原本在Flask上运行的应用程序直接部署为无服务器应用,这真是太厉害了!
AppSync~~~~~!!! (同步应用)