Getting 415 error when trying to send JSON data to Spring boot

Viewed 29

I seem to be getting a 415 Unsupported MediaType error when trying to send JSON data to my spring boot application.

Here's the React code which sends the data so far:

const [job, setJob] = useState({
    name: "",
});

const handleChange = (event) => {
    setJob({...job, [event.target.name] : event.target.value});
}

...
fetch(SAVE_JOB_URL, {
            method: "POST",
            headers: {
                "Accept":"application/json",
                "ContentType":"application/json",
                "Authorization":sessionStorage.getItem("accessToken")
            },
            body: new URLSearchParams({
                "userId": sessionStorage.getItem("userId"),
                "job": JSON.stringify(job),
            })
        })
        .then((response) => response.json())
        .then((responseData) => {
            console.log(JSON.stringify(responseData))
        })
        .catch(error => console.error(error));

This is the receiving code in my spring boot application:

@PostMapping("/job/save", consumes = [APPLICATION_JSON_VALUE])
fun saveJob(@RequestBody form: JobSaveForm): ResponseEntity<Job> {
    form.job.createdBy = userService.getUser(form.userId)

    val uri: URI = URI.create(ServletUriComponentsBuilder.fromCurrentContextPath().path("/api/job/save").toUriString())
    return ResponseEntity.created(uri).body(jobService.saveJob(form.job))
}

data class JobSaveForm(
    val userId: Long,
    val job: Job,
)

As soon as I send it this is what I get from SB's console:

2022-09-06 23:17:52.843 DEBUG 14776 --- [nio-8102-exec-8] o.s.web.servlet.DispatcherServlet        : POST "/api/job/save", parameters={masked}
2022-09-06 23:17:52.845  WARN 14776 --- [nio-8102-exec-8] .w.s.m.s.DefaultHandlerExceptionResolver : Resolved [org.springframework.web.HttpMediaTypeNotSupportedException: Content type 'application/x-www-form-urlencoded;charset=UTF-8' not supported]
2022-09-06 23:17:52.845 DEBUG 14776 --- [nio-8102-exec-8] o.s.web.servlet.DispatcherServlet        : Completed 415 UNSUPPORTED_MEDIA_TYPE
2022-09-06 23:17:52.846 DEBUG 14776 --- [nio-8102-exec-8] o.s.web.servlet.DispatcherServlet        : "ERROR" dispatch for POST "/error", parameters={masked}
2022-09-06 23:17:52.847 DEBUG 14776 --- [nio-8102-exec-8] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped to org.springframework.boot.autoconfigure.web.servlet.error.BasicErrorController#error(HttpServletRequest)
2022-09-06 23:17:52.850 DEBUG 14776 --- [nio-8102-exec-8] o.s.w.s.m.m.a.HttpEntityMethodProcessor  : Using 'application/json', given [application/json] and supported [application/json, application/*+json, application/json, application/*+json]
2022-09-06 23:17:52.852 DEBUG 14776 --- [nio-8102-exec-8] o.s.w.s.m.m.a.HttpEntityMethodProcessor  : Writing [{timestamp=Tue Sep 06 23:17:52 BST 2022, status=415, error=Unsupported Media Type, trace=org.springf (truncated)...]
2022-09-06 23:17:52.853 DEBUG 14776 --- [nio-8102-exec-8] o.s.web.servlet.DispatcherServlet        : Exiting from "ERROR" dispatch, status 415

The main part of that error message I'm picking up on is the Content type 'application/x-www-form-urlencoded part which got me thinking... Maybe I'm sending it incorrectly.

So I tried this instead:

fetch(SAVE_JOB_URL, {
    method: "POST",
    headers: {
        "Accept":"application/json",
        "ContentType":"application/json",
        "Authorization":sessionStorage.getItem("accessToken")
    },
    body: JSON.stringify({
        "userId":sessionStorage.getItem("userId"),
        "job": job
    })
})
.then((response) => response.json())
.then((responseData) => {
    console.log(JSON.stringify(responseData))
})
.catch(error => console.error(error));

However, that Content type 'application/x-www-form-urlencoded' turns into Content type 'text/plain' instead.

I feel I'm on the right track but I'm not sure where I'm quite going wrong.

1 Answers

It looks like you have a header with wrong name: try to change ContentType to Content-Type:

fetch(SAVE_JOB_URL, {
            method: "POST",
            headers: {
                "Accept":"application/json",
                "Content-Type":"application/json",
                "Authorization":sessionStorage.getItem("accessToken")
            },
            body: ...

Without this header your app tries to define content type automatically based on the actual request body type.

Related