Skip to content

RestfulController returns wrong contentType text/html instead of json #15172

@codeconsole

Description

@codeconsole

RestfulController has bad logic for json requests

Performing a application/json save or update request with multipartForm data results in a text/html response.
For modern REST usage it’s a leaky abstraction—mixing input and output negotiation leads to surprising 302s.

Either the redirect logic should change for json requests or the default response type binding should change.

request.withFormat {
form(multipartForm {
flash.message = message(code: 'default.created.message', args: [classMessageArg, instance.id])
redirect instance
})
'*' {
response.addHeader(HttpHeaders.LOCATION,
grailsLinkGenerator.link(resource: this.controllerName, action: 'show', id: instance.id, absolute: true,
namespace: hasProperty('namespace') ? this.namespace : null))
respond(instance, [status: CREATED, view: 'show'])
}

With that logic:

curl -i -L -X POST 'http://localhost:8081/user/save' \
  -H 'Content-Type: application/x-www-form-urlencoded; charset=UTF-8' \
  -H 'User-Agent: Mozilla/5.0 (iPhone; CPU iPhone OS 17_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148' \
  -H 'Accept: application/json' \
  --data 'name=Sample'

results in

<!doctype html>
<html lang="en" class="no-js">
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
    <meta http-equiv="X-UA-Compatible" content="IE=edge"/>
    <title>
    Show User
    </title>
</head>
<body>
....

even a subsequent get request returns text/html

curl -i 'http://localhost:8081/user/shoe/1' \
  -H 'User-Agent: Mozilla/5.0 (iPhone; CPU iPhone OS 17_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148' \
  -H 'Accept: application/json'

instead of what is expected

{"id":6,"name":"Sample"}

This is due to
User-Agent: Mozilla/5.0 (iPhone; CPU iPhone OS 17_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148 which is Safari web browser.

A decision needs to be made:
Should json save/update events result in redirects when json is requested?

A default grails app has the following yml

grails:
    mime:
        disable:
            accept:
                header:
                    userAgents:
                        - Gecko
                        - WebKit
                        - Presto
                        - Trident

Supposedly that configuration is there because Grails was configured to disable Accept header processing for certain user agents (Gecko, WebKit, Presto, Trident) - a legacy workaround for old browser quirks that's no longer needed and was breaking API clients.

But removing WebKit has no impact on results. That is because that is the default behavior which can be overridden like this:

  grails:
      mime:
          disable:
              accept:
                  header:
                      userAgents: []

These defaults were introduced 11 years ago. Is this still necessary in 2025?

private static void useDefaultConfig() {
disableForUserAgents = ~/(Gecko(?i)|WebKit(?i)|Presto(?i)|Trident(?i))/
useAcceptHeaderXhr = true
useAcceptHeader = true
}

If so, RestfulController logic should be rewritten to stop the redirect on save. Forcing .json format at the end of the url does not work because it is lost in the redirect.

Version

7.0.0

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    Status

    No status

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions