タイトル : Next.js FastAPIと通信 その3 複数ファイルのアップロード
更新日 : 2024-02-10
カテゴリ : プログラミング
タグ :
frontend   
nextjs   
zustand   
python   
fastapi   

画面

FastAPIの通信で複数ファイルをアップロードします。バックエンドでは何か処理するわけではなく、画面で指定された行数かサイズを求めて返すだけです。

画像1

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>
  );

}