はじめに
FastAPIで
これまで WEB APIは Flaskで作ってきましたが、調べているとfastAPIを使う方が、便利なようです。非同期処理がどうたらとかいろいろあるようですが、個人的に一番響いたのは、http://localhost:8080/docs と開くと、自作のWEB APIのマニュアルやテストができてしまうことです。これはもうチュートリアルをたどるとすぐできるので、書くのは省略するか後回し。これに感動しました。
今回、FastAPIでファイルをアップロードして保存する方法を少し調べたのでメモしておきます。
ファイルのアップロード
Request File (tutorial)
Tutorial に書いてあることのコピーなのですが、まぁ自分のメモです。
FastAPI Tutorial-User Guide の [Request File]
(https://fastapi.tiangolo.com/tutorial/request-files/) のページです。
from fastapi import FastAPI, File, UploadFile, Form
app = FastAPI()
@app.post("/files/")
async def create_file(file: bytes = File(...)):
return {"file_size": len(file)}
@app.post("/uploadfile/")
async def create_upload_file(file: UploadFile = File(...)):
return {"filename": file.filename}
下記のコードはtutorial にあるものです。私の環境では下記で動きました。bytes や UploadFileを引数にすれば良さそうです。
python3 -m pip install uvicorn, fastap
python3 -m uvicorn main:app --reload
上記のサーバを起動中に、適当に同じディレクトリにある16M bytes 位のファイルを指定してみると、
$ curl -X POST "http://127.0.0.1:8000/files/" -H "accept: application/json" -H "Content-Type: multipart/form-data" -F "file=@archive.zip;type=application/x-zip-compressed"
{"file_size":16957046}
と返ってきました。
一時ファイルの保存
UploadFile
の file をshutil.copyfileobj()
すれば良いようです。
ここに一時ファイルに保存する例があったので、動かしてみたら動きました。
https://github.com/tiangolo/fastapi/issues/426
from fastapi import FastAPI, File, UploadFile, Form
import shutil
from pathlib import Path
from tempfile import NamedTemporaryFile
@app.post("/saveuploadfile/")
async def save_upload_file_tmp(fileb: UploadFile=File(...), token:str=Form(...)):
tmp_path:Path = ""
try:
print(type(fileb))# <class 'starlette.datastructures.UploadFile'>
print(type(fileb.file)) #<class 'tempfile.SpooledTemporaryFile'>
suffix = Path(fileb.filename).suffix
with NamedTemporaryFile(delete=False, suffix=suffix) as tmp:
shutil.copyfileobj(fileb.file, tmp)
tmp_path = Path(tmp.name)
print(tmp_path)
finally:
fileb.file.close()
return {
"filename": fileb.filename,
"temporary_filepath": tmp_path,
"token": token,
"fileb_content_type": fileb.content_type,
}
別ターミナルで動かすと、
$ curl -X POST "http://127.0.0.1:8000/saveuploadfile/" -H "accept: application/json" -H "Content-Type: multipart/form-data" -F "token=agd" -F "fileb=@archive.zip;type=application/x-zip-compressed"
responce body が
{
"filename": "archive.zip",
"temporary_filepath": "/tmp/tmp2ki9kvdp.zip",
"token": "agd",
"fileb_content_type": "application/x-zip-compressed"
}
と返ってきます。
まとめ
とりあえずfastAPIでファイルのアップロードはできた。明日の作業も何とか進められそうだ。
まだまだ試せていないのは以下の通り。
- fileのサイズの取得方法が分からない。一応、tempfile(https://docs.python.org/3/library/tempfile.html)
を読んではみたのだが。 - 複数ファイルの取り扱い。これはTutorial にあったので、試せばよいだけだと思うが。
- ダウンロードもしたい。
(2021/02/08)