以无服务器方式使用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
        }
      }
    }
  }
}
スクリーンショット 2017-12-21 16.57.59.png

我成功地查询了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控制台界面,与之前相同。

スクリーンショット 2017-12-21 17.58.56.png

当你在左边位置输入之前在本地确认过的查询并运行,我想你会得到类似的结果。

留心

当我在本地测试时,我会在Flask启动时检查是否存在DynamoDB表,如果不存在,就创建一个。然而,在转为无服务器后,它不会处理这个步骤,所以如果表不存在,就需要自己创建。由于我将本地创建的表从无服务器应用程序中重新使用,所以我认为这没有问题。

资源删除使用 $ zappa undeploy。

总结

用Zappa可以将原本在Flask上运行的应用程序直接部署为无服务器应用,这真是太厉害了!

AppSync~~~~~!!! (同步应用)

广告
将在 10 秒后关闭
bannerAds