🍓
FastAPI + Strawberry(Graphql)でFileUploadのtest作成
Intro
FastAPI + strawberryで簡単なgraphqlサーバーを作ってたらFileUploadのtest file作成に困ったので調べてみました。
公式文書ではschemaだけを用いたtestの仕方は書いてあるけどfile uploadに関しては書いてなかった。
ただ、file_uploadの部分からgraphql-multipart-request-specという文書がリンクされていて読んでみたらgraphqlでファイルをアップロードするときはmultipart/form-dataの形式でrequestする必要があると書いてあってstrawberryもそれに従っていることだった。
Graphql multipart/form-dataの形式
{
"operations":"{query, variables}",
"map":'{"file_0":["variables.file"]}',
"file_o":FILE
}
FastAPI TEST
公式文書によるとfastapiのTestClient
はrequests
と同じ使い方をしている。
Use the
TestClient
object the same way as you do withrequests
.
requests
モジュールでmultipart/form-data
をrequestするときはfiles
argを使う。
TESTING
Schemaの作成
import strawberry
from strawberry.file_uploads import Upload
from typing import List
@strawberry.type
class UploadSuccess:
result:str = "OK"
filename:str
@strawberry.type
class Mutation:
@strawberry.mutation
async def test_single_upload(self, myfile: Upload) -> UploadSuccess:
filename = myfile.filename
return UploadSuccess(filename=filename)
async def test_multiple_upload(self, myfiles: List[Upload]) -> List[UploadSuccess]:
return [
UploadSuccess(filename=myfile.filename)
for myfile in myfiles
]
single fileの場合
from fastapi.testclient import TestClient
import json
client = TestClient(app) # appはgraphqlのrouteを含めているapp object
query = """
mutation MyMutation($file:Upload!){
testSingleUpload(myfile:$file){
result
filename
}
}
"""
variables = {'file':None}
def test_file_upload():
file = open("testfile","rb")
response = client.post('/graphql',
files=dict(
operations=(None, json.dumps({
'query':query,
'variables': variables
})),
file=file,
map=(None, json.dumps({
'file': ['variables.file']
}))
)
)
assert response.status_code == 200
Multiple Fileの場合
from fastapi.testclient import TestClient
import json
client = TestClient(app) # appはgraphqlのrouteを含めているapp object
query = """
mutation MyMutation($file:[Upload!]!){
testSingleUpload(myfiles:$files){
result
filename
}
}
"""
variables = {'files': [None, None]}
def test_file_upload():
file0 = open("testfile0","rb")
file1 = open("testfile1", "rb")
response = client.post('/graphql',
files=dict(
operations=(None, json.dumps({
'query':query,
'variables': variables
})),
file0=file0,
file1=file1,
map=(None, json.dumps({
'file0': ['variables.files.0'],
'file1': ['variables.files.1']
}))
)
)
assert response.status_code == 200
Discussion