0
votes

I'm wondering about this, and it's something that I ran into before and just worked around w/ a bunch of line-by-line mappings.

Say I want a Grails 3.3 app with a few screen (pages) using the old / standard mapping of:

static mappings = {

        "/$controller/$action?/$id?(.$format)?"{
            constraints {
                // apply constraints here
            }
        }
}

But then I would also like an (very small) API style mapping, something like:

static mappings = {
    get "/api/$controller(.$format)?"(action:"index", namespace:'api')
    get "/api/$controller/$id(.$format)?"(action:"show", namespace:'api')
    post "/api/$controller"(action:"save", namespace:'api')
    put "/api/$controller/$id"(action:"updateStatus", namespace:'api')
    patch "/api/$controller/$id"(action:"patch", namespace:'api')
    delete "/api/$controller/$id"(action:"delete", namespace:'api')
}

The normal controllers don't have a namespace, and I'd like them accessed via the grails default style. But I'd like to have the API accessible (including reverse mapping using createLink() etc if possible to keep things simple.

I've tried a number of configurations, and I've found that the following gets a forward mapping (controller and action is found via URL) but the reverse mapping is always defaulting to the "/$controller/$action?/$id?(.$format)?" style link (which I would prefer to generate a 404 for these, although I'm ok with it continuing to be accessible). E.g. complete code is:

class UrlMappings {

    static mappings = {

        get "/api/$controller(.$format)?"(action:"index", namespace:'api')
        get "/api/$controller/(.$format)?"(action:"index", namespace:'api')
        get "/api/$controller/$id(.$format)?"(action:"show", namespace:'api')
        post "/api/$controller"(action:"save", namespace:'api')
        put "/api/$controller/$id"(action:"updateStatus", namespace:'api')
        patch "/api/$controller/$id"(action:"patch", namespace:'api')
        delete "/api/$controller/$id"(action:"delete", namespace:'api')


        "/$controller/$action?/$id?(.$format)?"{
            constraints {
                // apply constraints here
            }
        }


        "/"(view:"/index")
        "500"(view:'/error')
        "404"(view:'/notFound')
    }
}

Is there anyway to get this working in the manner I'm wanting - e.g. to have a reverse URL - e.g. createLink(...) work? I think at one point on another app I'd used named mappings, but those seem to get out of hand a bit quickly.

Currently if I do

"${createLink(namespace:'api', controller:'upload', action:'post')}"

The result is /upload/post when what I want is /api/upload

Final (hopefully edit) - this appears to be a bit bigger than just the URLs coming out in a format I don't want using reverse mapping. While forward mapping "works" with just the controller, when I turn on Grails Spring security I'm getting access denied on the /api/upload versions of the URL, I'm not 100% sure, but looking at the logs it appears to be because code can't find the controller and thus the @Secured annotation.

1
The "normal" controllers don't have any namespace while the API controllers are all namespaced to 'api'. Is there anyway to get this working and have a reverse URL - e.g. createLink(...) work? - It isn't clear what you mean by "working" and what isn't working.Jeff Scott Brown
Ah, I will update with more code. At the moment, I checked and forward mapping is fine, but reverse mapping isn't.Robert
You have createLink(namespace:'api', controller:'upload', action:'post'). Is the action in your controller that you want to link to named post? Also, there isn't enough info in your question to know for sure but you may want to specify the HTTP method with something like createLink(namespace:'api', controller:'upload', action:'post', method: 'POST')Jeff Scott Brown

1 Answers

0
votes

Ok, so the answer is to get the url mappings report plugin, or alternatively someone else to check your code.

Basically this was a typo on my end, the last configuration I had is working well enough once corrected.

First - with the security plugin you get a 403 instread of a 404.

Second, the reverse mapping via createLink is returning a dummy URL instead of reporting an error (e.g. if there is no controller that matches, say due to said typo).