Search code examples
pythonreactjspostaudiostarlette

Starlette - Type Error: FormData object is not callable


I'm uploading an audio file to a Starlette server and I'm trying to access it the way they recommend in the docs, but it's giving me a not callable error. I gather the issue is calling .form() on the request object, but I'm not sure how else to read it in.

Server Route:

@app.route('/api/upload_track/', methods=['POST'])
async def separate_vocals(request):
    audio_data = await request.form()
    separator = Separator('spleeter:2stems')
    audio_bytes = await (audio_data['file'].read())
    return audio_data

Client:

function FileUploadSingle() {
  const [file, setFile] = useState([]);

  const handleFileChange = (e) => {
    if (e.target.files) {
      setFile(e.target.files[0]);
    }
  };
   
    let audioData = new FormData();

    const blob = new Blob([file], {type: 'audio/mpeg'});
    audioData.append('file', file, 'file');
    console.log(file);
    console.log(audioData.get('file'));
    // 👇 Uploading the file using the fetch API to the server
    fetch(`${RESTAPI_URL}/api/upload_track/`, {
      method: 'POST',
      body: audioData, 
    })
      .then((res) => res.json())
      .then((data) => console.log(data))
      .catch((err) => console.error(err));
  };

}

export default FileUploadSingle;

Solution

  • The following error:

    TypeError: 'FormData' object is not callable
    

    is caused when returning the FormData object you obtained, by using await request.form(), from your endpoint (i.e., return audio_data)—which I am sure it is not the one you would like to return in the first place, but rather the audio_bytes. Now, if you attempted to return the byte array using return audio_bytes, you would get:

    TypeError: 'bytes' object is not callable
    

    In Starlette, you could use the Response class to return bytes, for example:

    from starlette.responses import Response
    
    @app.route('/upload', methods=['POST'])
    async def upload(request):
        form = await request.form()
        contents = await form['file'].read()
        return Response(contents)
    

    The Response class also allows you to specify the MIME type (also known as media type), using the media_type parameter.