11
5

More than 1 year has passed since last update.

React + FastAPI で画像のアップロード&保存機能を実装

Last updated at Posted at 2022-08-21

はじめに

Reactの初学者です。

画像のアップロードと保存機能を実装する際に結構詰まったので、備忘録として残しておきます。
フロントエンドはReact、バックエンドはFastAPIで実装します。

コードは初心者っぽいところが多いと思われます。ご了承ください。

React

まずは全体のコード。
formタグ内で画像を選択した後、Submitボタンを押すとAPIリクエストが送信されます。

my-app/src/components/SubmitImage.jsx
import React from 'react'
import { useState } from 'react'
import 'bulma/css/bulma.min.css' // css

export const SubmitImage = () => {
    const [image, setImage] = useState()
    const [errorMessage, setErrorMessage] = useState('')
    const URL = 'http://127.0.0.1:8000/images/' //適宜設定

    const getImage = (e) => {
        if(!e.target.files) return
        const img= e.target.files[0]
        setImage(img)
    }
    const Submit=async()=>{
        const formdata = new FormData()
        formdata.append('upload_file', image)
        const requestOptions={
            method:"POST",
            body:formdata,
        }
        const response =await fetch(URL,requestOptions)
        const data=await response.json()
    }
    const handleSubmit=(e)=>{
        e.preventDefault()
        Submit()
    }
    

    return (
        <div>
        <form className="box" onSubmit={handleSubmit}>
            <label className="label" htmlFor="img">画像</label>
            <div>
                <input id="img" type="file" accept="image/*,.png,.jpg,.jpeg,.gif" onChange={getImage}/>
            </div>
            <br/>
            <button className="button is-primary" type="submit">Submit</button> 
        </form>
        <ErrorMessage message={errorMessage}></ErrorMessage>
        </div>
    )
}

ポイントはここ。

const Submit=async()=>{
        const formdata = new FormData()
        formdata.append('upload_file', image)
        const requestOptions={
            method:"POST",
            body:formdata,
        }
        const response =await fetch(URL,requestOptions)
        const data=await response.json()
    }
  • FormDataオブジェクトにuploadされた画像をappendする。

    • このときのkey='upload_file'はFastAPI側で使用します。
  • requestOptionsにはheadersを指定しない。

    • "Content-Type":"multipart/form-data"は記載しないほうが良い。
    • 指定すると 400 Bad Requestを吐かれます。

見た目

スクリーンショット 2022-08-21 100044.jpg

FastAPI

続いてバックエンド側

api/main.py
from fastapi import FastAPI,UploadFile
import shutil

app=FastAPI()

# ~~~~~~ 省略 ~~~~~~~~

@app.post("/images/")
def get_uploadfile(upload_file: UploadFile): # フロント側のFormDataのkeyに合わせる(upload_file)
    path = f'api/files/{upload_file.filename}'# api/filesディレクトリを作成しておく
    with open(path, 'wb+') as buffer:
        shutil.copyfileobj(upload_file.file, buffer)
    return {
        'filename': path,
        'type': upload_file.content_type
    }

FastAPIに画像を保存する機能は無く、shutilでコピーして保存するようです。

つまづいた点

フロント側とバックエンド側でformDataのkey値を揃える必要がある。
すなわち、

  • React
    formdata.append('upload_file', image)
  • FastAPI
    def get_uploadfile(upload_file: UploadFile):

のように、上記の例ではupload_fileと揃える。

これに気づかず、422 unprocessable entity を永遠に吐かれていました。。。

11
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
11
5