Search code examples
spring-bootfetch-apimultipartform-datacontent-typeform-data

Sending data to the Spring Boot backend with FormData and RequestParam not working


So I am struggling for a while with sending files and other data to the backend with FormData in the frontend and RequestParam in the backend. I tried so many different things and I have searched so long for solutions and nothing that could fix it. I already made sure that the values are not empty by way of console.logs.

Code:

//Front-End
async addProduct(itemDetails) {
        const url = `${this.resourcesUrl}/addProduct`;

        const formData = new FormData();
        formData.append('name', itemDetails.name);
        formData.append('description', itemDetails.description);
        formData.append('file1', itemDetails.file1);
        formData.append('file2', itemDetails.file2);

        const response = await fetch(url, {
            method: 'POST',
            body: formData,
        });

        if (response.ok) {
            return await response.json();
        } else {
            const errorResponse = await response.json();
            throw new Error(errorResponse.message || 'Failed to add product');
        }
    }


//Back-End
@PostMapping("/addProduct")
    public ResponseEntity<Product> addProduct(
            @RequestParam(value = "name") String name,
            @RequestParam(value = "description") String description,
            @RequestPart(value = "file1") MultipartFile file1,
            @RequestPart(value = "file2") MultipartFile file2
    ) {
        try {
            String file1Path = fileStorageService.saveFile(name, file1);
            String file2Path = fileStorageService.saveFile(name, file2);

            Product product = new Product(name, description, file1Path , file2Path);

            productRepository.save(product);

            return ResponseEntity.ok(product);
        } catch (Exception e) {
            return ResponseEntity.badRequest().build();
        }
    }

pom and application.properties:

//relavant part of application.properties
spring.servlet.multipart.enabled=true
spring.servlet.multipart.max-file-size=10MB
spring.servlet.multipart.max-request-size=10MB


//pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>3.2.2</version>
        <relativePath/>
    </parent>
    <groupId>com.example</groupId>
    <artifactId>app</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>app</name>
    <description>Demo project for Spring Boot</description>
    <properties>
        <java.version>22</java.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>

        <!-- JWT jackson -->
        <dependency>
            <groupId>io.jsonwebtoken</groupId>
            <artifactId>jjwt-api</artifactId>
            <version>0.11.2</version>
        </dependency>
        <dependency>
            <groupId>io.jsonwebtoken</groupId>
            <artifactId>jjwt-impl</artifactId>
            <version>0.11.2</version>
        </dependency>
        <dependency>
            <groupId>io.jsonwebtoken</groupId>
            <artifactId>jjwt-jackson</artifactId>
            <version>0.11.2</version>
            <scope>runtime</scope>
        </dependency>
        <!-- end JWT jackson -->

        <dependency>
            <groupId>jakarta.persistence</groupId>
            <artifactId>jakarta.persistence-api</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-tomcat</artifactId>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>
        <dependency>
            <groupId>com.h2database</groupId>
            <artifactId>h2</artifactId>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-websocket</artifactId>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

So when I try to add a new product with this values:

name: Test description: Test file1: (file1) file2: (file2)

I get the error: "Required request parameter 'name' for method parameter type String is not present"

The Content-Type of Request Headers in the network tab is application/json but from what I understand is that it should be automatically set to multipart/form-data but it does not do that, even if I explicitly set the Content-Type in the fetch request to multipart/form-data. I think that this is the reason that the passed parameter value is not being recognized.


Solution

  • After having this issue for so long I found out it had to do with a fetch interceptor implementation in my codebase (it sets in each fetch explicitly as Content-Type: application/json) and after removing the explicit Content-Type it worked.

    So if you also have this problem you should look if you did set the Content-Type explicitly anywhere in your codebase.