Send FormData object and File in a single Axios POST request

Viewed 182

I currently have a Spring boot API controller method (below) that accepts an object as well as a MultiPart file. I am able to successfully send a POST request via Postman however I am now struggling to make this post request via my front-end ReactJS application using Axios.

@PostMapping(
        path = "/upload",
        consumes = {
                MediaType.APPLICATION_JSON_VALUE,
                MediaType.MULTIPART_FORM_DATA_VALUE
        },
        headers = {
                "Content-Type=multipart/form-data"
        }
)
public SoundProfile uploadSoundProfile(Authentication auth,
                               @RequestPart("soundProfileRequest") SoundProfileRequest soundProfileRequest,
                               @RequestPart("audio_file") MultipartFile audio_file){

    return soundProfileService.uploadSoundProfile(auth, soundProfileRequest, audio_file);
}

Postman POST request: enter image description here

The following is my service method to process the object and file which is responsible for saving the object to a MySQL database and then storing the file in an Amazon S3 bucket.

public SoundProfile uploadSoundProfile(Authentication auth, SoundProfileRequest soundProfileRequest, MultipartFile audio_file) {

    if (audio_file.isEmpty()){
        throw new IllegalStateException("no audio file received");
    }


    AppUser current_user = appUserRepository.findByEmail(auth.getName())
            .orElseThrow(
                    () -> new IllegalStateException("User not found")
            );

    Map<String, String> metadata = new HashMap<>();
    metadata.put("Content-Type", audio_file.getContentType());
    metadata.put("Content-Length", String.valueOf(audio_file.getSize()));

    
    String soundPath = UUID.randomUUID().toString();

    SoundProfile soundProfile = new SoundProfile(
            soundPath, // SoundPath = S3 key
            soundProfileRequest.getCaseBrand(),
            soundProfileRequest.getCaseModel(),
            soundProfileRequest.getSwitches(),
            soundProfileRequest.getKeycaps(),
            soundProfileRequest.getStabilizers(),
            soundProfileRequest.getLube(),
            soundProfileRequest.getMods(),
            current_user
    );

    // save sound profile to database
    soundProfileRepository.save(soundProfile);


    String path = String.format("%s/%s", BucketName.KEYBOARD_AUDIO_BUCKET.getBucketName(), current_user.getUserId());
    String filename = String.format("%s-%s", audio_file.getOriginalFilename(), soundPath);

    // Save audio file to s3 bucket
    try {
        fileStore.saveAudio(
                path,
                filename,
                Optional.of(metadata),
                audio_file.getInputStream()
        );
    } catch (IOException e) {
        throw new IllegalStateException(e);
    }

    return soundProfile;
}

I would like to send the SoundProfileRequest object and the multipart file separately, meaning I don't want to append the file to a FormData object, but I would still like to send the file along with the form fields in a single post request.

For example in my front-end React Component:

export default function UploadSoundProfile() {

const [caseBrand, setCaseBrand] = useState("");
const [caseModel, setCaseModel] = useState("");
const [switches, setSwitches] = useState("");
const [keycaps, setKeycaps] = useState("");
const [lube, setLube] = useState("");
const [stabilizers, setStabilizers] = useState("");
const [mods, setMods] = useState("");

const [selectedFile, setSelectedFile] = useState("");
const history =  useHistory();


const createSoundProfile = (e) => {
    
    e.preventDefault();

    const url = "/sound-profile/upload";
    const formData = new FormData();

    formData.append('caseBrand', caseBrand);
    formData.append('caseModel', caseModel);
    formData.append('switches', switches);
    formData.append('keycaps', keycaps);
    formData.append('lube', lube);
    formData.append('stabilizers', stabilizers);
    formData.append('mods', mods);


    **// SHOULD FILE ALSO BE APPENDED TO FORMDATA OBJECT HERE?**
    formData.append('audio_file', selectedFile);

    const config = {
        headers: {
            "content-type": "multipart/form-data"
        }
    }

    uploadProfileService.createSoundProfile(url, formData, config);

    history.push("/sound-profile/profile");
};

return (
   ...
)

}

Is there a way to make the POST request with Axios without appending the file to the FormData object while still making a single post request?

I am unsure of how to accomplish this, or if it is possible. I have seen other posts where a file is being .append() to a FormData object, but I am unsure if this will cause an error on the backend.

Thanks for any help in advance!

0 Answers
Related