タイトル : Next.js FastAPIと通信 その3 複数ファイルのアップロード
更新日 : 2024-02-10
カテゴリ : プログラミング
画面
FastAPIの通信で複数ファイルをアップロードします。バックエンドでは何か処理するわけではなく、画面で指定された行数かサイズを求めて返すだけです。
FastAPIの方
Bodyを使うの初めてです。FastAPIで作るWebアプリ - Body validationを参照しました。
@app.post("/upload")
async def post_upload( type: str=Body(...), files: list[UploadFile]=[]):
rv = []
for file in files:
data = file.file.read()
if type == "byte":
fsize = len(data)
else:
data_str =data.decode()
lines = data_str.splitlines()
fsize = len(lines)
rv.append( {
"name": file.filename,
"type": type,
"value": fsize
})
return {"rv": rv}
Next.jsの方
"use client"
import * as React from 'react';
import { Typography, Stack, Button } from "@mui/material";
import InputLabel from '@mui/material/InputLabel';
import MenuItem from '@mui/material/MenuItem';
import FormControl from '@mui/material/FormControl';
import Select, { SelectChangeEvent } from '@mui/material/Select';
import { API_URL } from "@/store/settings";
export default function Home() {
const [resType, setResType] = React.useState('line');
const [resultText, setResultText] = React.useState('');
const handleChange = (event: SelectChangeEvent) => {
setResType(event.target.value as string);
};
const handleSelectedFile = async (event: any) => {
const files: File[] = Array.from(event.target.files);
const file_list:Blob[] = []
const data = new FormData();
const myHeaders = new Headers();
myHeaders.append('Content-Type','multipart/form-data');
for (let i = 0; i < files.length; i++) {
file_list.push(files[i])
data.append("files", files[i] , files[i].name)
}
console.log(file_list)
data.append("type", resType);
const myInit:RequestInit = {
method: 'POST',
body: data,
};
const fetchUpload: any = async (myRequest: Request) => {
try {
console.log(myRequest)
const response = await fetch(myRequest);
return await response.json()
} catch (error) {
console.error("Error fetching tables:", error);
return error
}
}
const myRequest = new Request(`${API_URL}/upload`, myInit);
const response = await fetchUpload(myRequest);
setResultText(JSON.stringify(response))
};
return (
<Stack>
<Stack padding={3} spacing={2} width={150}>
<Typography>アップロードの画面</Typography>
<FormControl fullWidth>
<InputLabel id="demo-simple-select-label">取得項目</InputLabel>
<Select
labelId="demo-simple-select-label"
id="demo-simple-select"
defaultValue={"line"}
label="size"
size = "small"
onChange={handleChange}
>
<MenuItem value={"byte"}>byte</MenuItem>
<MenuItem value={"line"}>line</MenuItem>
</Select>
</FormControl>
<Button component="label" variant="contained">
Upload file
<input type="file" onChange={handleSelectedFile} hidden multiple />
</Button>
</Stack>
<Stack padding={3} spacing={2}>
<Typography key="textResult">{resultText}</Typography>
</Stack>
</Stack>
);
}