将MongoDB与Fast API一起使用


本文是东京学业大学桥山实验室2020年出现日历第22天的文章。

介绍

您正在使用FastAPI吗? ??
Django,Flask等经常在python Web框架中使用,但这一次是有关Fast API的文章。
对于与RDS的连接,文档中引入了一个称为SQLAlchemy(Mysql)的ORM,但是这次我们将使用pymongo与MongoDB连接并执行CRUD操作。
使用mongo express进行检查,该显示器可以使用GUI操作MongoDB,并使用Fast API的自动生成文档(Swagger UI)。
执行将使用Docker构建。单击此处获取GitHub。

开发环境

  • MacOs:Mac mini(2018)macOS Big Sur版本11.1
  • 码头工人:20.10.0
  • 码头工人组成:1.27.4
  • MongoDB的:4.2

1准备

1.1目录结构

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
.
├── Makefile
├── README.md
├── docker
│   ├── docker-compose.yml
│   ├── fast_api
│   │   └── Dockerfile
│   ├── mongo-express
│   │   └── Dockerfile
│   ├── mongo_db
│   │   ├── Dockerfile
│   │   ├── configdb
│   │   ├── db
│   │   └── mongo-init.js
│   └── wait-for-it.sh
└── fast_api
    ├── Makefile
    ├── __init__.py
    ├── __pycache__
    ├── app.py
    ├── database.py
    ├── requirements.txt
    ├── routers
    │   ├── __init__.py
    │   ├── __pycache__
    │   └── posts.py
    ├── sample-json
    │   ├── sample.json
    │   └── update.json
    └── tests
        ├── __pycache__
        └── test_initial.py

docker-compose.yml和每个Dockerfile放置在

泊坞目录中。 mongo的db数据也放置在这里。
另外,在docker-compose中的执行是在根目录的Makefile中执行的。

1.2准备文件

每个文件的内容如下。

制作文件

生成文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
.PHONY: setup
setup:
    docker-compose -f docker/docker-compose.yml build
    $(MAKE) install

.PHONY: install
install:
    docker-compose -f docker/docker-compose.yml run --rm fast_api make setup

.PHONY: start
start:
    docker-compose -f docker/docker-compose.yml up --remove-orphans

.PHONY: start.background
start.background:
    docker-compose -f docker/docker-compose.yml up -d --remove-orphans

.PHONY: stop
stop:
    docker-compose -f docker/docker-compose.yml down

.PHONY: pytest
pytest:
    docker-compose -f docker/docker-compose.yml run --rm fast_api make test

fast_api / Makefile

1
2
3
4
5
6
7
# pipでの依存関係の解決 (.pipディレクトリに依存関係を全て入れる)
setup:
    pip3 install --upgrade pip
    pip3 install -r requirements.txt -t ./.pip

test:
    python -m pytest -v

使用的命令如下。
-使用setup 获取软件包
-使用start 运行应用程序
-使用start.background 在后台运行应用程序
-使用stop 停止应用程序
-使用pytest

执行pytest

Dockerfile(3)

FastAPI

码头工人/ fast_api / Dockerfile

1
2
3
4
5
6
7
8
9
10
11
12
13
14
FROM python:3.7-alpine # alpineで軽量化

ENV LANG C.UTF-8
ENV TZ Asia/Tokyo

RUN apk add --update --no-cache make bash gcc g++ tzdata git\
  && pip install --upgrade pip \
  && pip install uvicorn==0.11.8

ENV PYTHONUNBUFFERED 1
ENV PYTHONPATH /app/.pip

ADD docker/wait-for-it.sh /usr/local/bin/wait-for-it.sh
RUN chmod +x /usr/local/bin/wait-for-it.sh
MongoDB

码头工人/ mongo_db / Dockerfile

1
FROM mongo:4.2

蒙哥快车

码头工人/ mongo_express /码头文件

1
2
3
4
FROM mongo-express

ADD wait-for-it.sh /usr/local/bin/wait-for-it.sh
RUN chmod +x /usr/local/bin//wait-for-it.sh

docker-compose.yml

泊坞窗/ docker-compose.yml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
version: "3.7"

services:
  fast_api:
    container_name: fast_api
    build:
      context: ../.
      dockerfile: ./docker/fast_api/Dockerfile
    working_dir: /app
    volumes:
      - ../fast_api:/app:cached
    ports:
      - 8000:8000
    tty: true
    environment:
      MONGO_DATABASE_NAME: mongodb
      MONGO_DATABASE_USER: root
      MONGO_DATABASE_PASSWORD: root
      MONGO_DATABASE_CONTAINER_NAME: mongo_db
      MONGO_DATABASE_PORT: 27017

    command: wait-for-it.sh mongo_db:27017 --timeout=30 -- uvicorn app:app --reload --host 0.0.0.0 --port 8000
    networks:
      - fastapi-mongo-network

  mongodb:
    container_name: mongo_db
    environment:
      MONGO_INITDB_ROOT_USERNAME: root
      MONGO_INITDB_ROOT_PASSWORD: root
    build:
      context: .
      dockerfile: ./mongo_db/Dockerfile
    ports:
      - 27017:27017
    tty: true
    volumes:
      - ./mongo_db/db:/data/db
      - ./mongo_db/configdb:/data/configdb
      - ./mongo_db/mongo-init.js:/docker-entrypoint-initdb.d/mongo-init.js
    networks:
      - fastapi-mongo-network

  mongo-express:
    container_name: mongo_express
    build:
      context: .
      dockerfile: ./mongo-express/Dockerfile
    environment:
      ME_CONFIG_MONGODB_ADMINUSERNAME: root
      ME_CONFIG_MONGODB_ADMINPASSWORD: root
      ME_CONFIG_MONGODB_SERVER: mongo_db
    ports:
      - 8081:8081
    tty: true
    command: wait-for-it.sh mongo_db:27017 --timeout=30 -- node app
    restart: unless-stopped
    networks:
      - fastapi-mongo-network

networks:
  fastapi-mongo-network:
    driver: bridge

等待Itsh

我是从这里借来的。
您可以等待其他容器启动后再启动它们(仅取决于顺序)。

document.txt

fast_api /要求。

1
2
3
4
5
6
7
aiofiles==0.6.0
fastapi==0.61.1
pymongo==3.11.0
pytest==6.1.0
python-dateutil==2.8.1
setuptools==49.2.0
uvicorn==0.11.8

描述所需的软件包。

apppy

fast_api /应用。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import uvicorn
from fastapi import FastAPI
from routers import posts

app = FastAPI(prefix="/")

app.include_router(posts.router, prefix="/post") # routingを階層的にし読み込む

@app.get('/')
def get_hello():
    return {'message': 'Hello from FastAPI Server!'}

if __name__ == '__main__':
    uvicorn.run(app, host="0.0.0.0", port=8000)

启动应用程序。在Flask中,使用Buleprint使路由分层,但是在FastAPI中,可以使用include_router添加路由。

posts.py

路由器/ posts.py

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
from fastapi import APIRouter, Body

from bson.objectid import ObjectId
from bson.json_util import dumps, loads

from database import db

router = APIRouter()
@router.post('')
def create_post(body=Body(...)):
    """postの作成

    ----------
    Parameters:

    body: body
        任意のjson
    """
    post = body['payload']
    db.posts.insert(post)
    return {'post': "ok"}

@router.get('')
def read_post():
    """postの取得

    ----------
    Parameters:

    なし
    """
    db_post = db.posts.find_one()
    return {'item': dumps(db_post)}

@router.get('/{id}')
def read_post_by_id(id: str):
    """postの取得(id)

    ----------
    Parameters:

    id: str
        オブジェクトID
    """
    db_post = db.posts.find_one({'_id': ObjectId(id)})
    print(db_post)
    return {'item': dumps(db_post)}

@router.put('')
def update_post(body=Body(...)):
    """postの更新(id)

    ----------
    Parameters:

    body: body
        任意のjson
    """
    post = body['payload']
    _id = post['_id']
    title = post['title']
    text = post['text']
    db.posts.update_one(
        {'_id': ObjectId(_id)},
        {'$set':
            {
                "title": title, 'text': text
            }
        }
    )
    return {'update': "ok"}

@router.delete('/')
def delete_post_by_id(id: str):
    """postの削除(id)

    ----------
    Parameters:

    id: str
        オブジェクトID
    """
    db.posts.delete_one(
        {'_id': ObjectId(id)}
    )
    return {'delete': "ok"}

描述帖子的CRUD。这次仅是确认,因此错误处理未完成???Λ?
写作风格与Flask相似,我觉得它很容易写。
您可以在Swagger UI中引用文档,因此可以很好地描述它(我不知道如何编写...)!
需要注意的是,从MongoDB获得的对象无法按原样转换为json格式,因此将执行转储。希望您可以将每个形状做成自己喜欢的形状。

数据库py

fast_api /数据库。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import os
from pymongo import MongoClient

MONGO_DATABASE_NAME = os.environ.get("MONGO_DATABASE_NAME")  # mongodb
MONGO_DATABASE_USER = os.environ.get("MONGO_DATABASE_USER")  # root
MONGO_DATABASE_PASSWORD = os.environ.get("MONGO_DATABASE_PASSWORD")  # root
MONGO_DATABASE_CONTAINER_NAME = os.environ.get(
    "MONGO_DATABASE_CONTAINER_NAME")  # mongo_db
MONGO_DATABASE_PORT = int(os.environ.get("MONGO_DATABASE_PORT"))  # 27017

DATABASE_URL = "%s://%s:%s@%s:%d" % (
    MONGO_DATABASE_NAME, MONGO_DATABASE_USER, MONGO_DATABASE_PASSWORD, MONGO_DATABASE_CONTAINER_NAME, MONGO_DATABASE_PORT)

client = MongoClient(DATABASE_URL)
db = client.first_test  #database名がfirst_test

描述与MongoDB的连接设置。每个环境变量都用docker-composer.yml设置。
由于MongoDB是NoSQL,它将创建尚未创建的任何内容。
使用pymongo可以很容易地描述它。
使用的数据库名称如下。

1
db = client.first_test  #database名がfirst_test

2运行应用程序

通过按以下顺序发出命令来启动应用程序。
这次
1.创建
2.阅读(无ID /具有ID)
3.更新
4.删除

我们将按

的顺序进行。

安慰

1
2
$ make setup
$ make start

访问

http://localhost:8000/docs并检查Swagger UI。
スクリーンショット 2020-12-22 12.14.59.png

3. CRUD操作

3.1创建

API执行

复制以下fast_api/sample-json/sample.json,将其放在Request正文中并执行。

fast_api / sample-json / sample.json

1
2
3
4
5
6
{
  "payload":{
    "title" : "初投稿!",
    "text" : "hogehoge"
  }
}

スクリーンショット 2020-12-22 12.18.50.png

检查MongoDB

访问

http://localhost:8081并检查MngoDB。
如果转到[first_test]-> [posts]-> [created post],则会找到以下文档。

スクリーンショット 2020-12-22 12.24.11.png

3.2读取(无ID /有)

没有ID

スクリーンショット 2020-12-22 12.27.36.png

编号

以先前创建的帖子的对象ID(确认帖子时为5fe1661f03100427fb1e8cd3)作为参数执行。

スクリーンショット 2020-12-22 12.29.03.png

3.3更新

同样,对象ID(确认帖子时为5fe1661f03100427fb1e8cd3)用作参数,但这次将通过将其放入json中来执行,因此更改fast_api/sample-json/update.json_id部分。 。

fast_api / sample-json / update.json

1
2
3
4
5
6
7
{
  "payload":{
    "_id" : "5fe1661f03100427fb1e8cd3",
    "title" : "投稿の編集",
    "text" : "fugefuge"
  }
}

スクリーンショット 2020-12-22 12.36.21.png

检查它是否已被mongo express更改。

スクリーンショット 2020-12-22 12.37.06.png

3.4删除

同样,执行对象ID(确认帖子时为5fe1661f03100427fb1e8cd3)作为参数

スクリーンショット 2020-12-22 12.38.13.png

检查是否已被mongo express删除。

スクリーンショット 2020-12-22 12.38.52.png

结尾

本文介绍使用带Fast API的MongoDB进行CRUD操作。
我很高兴您可以将其用作参考。