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.
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 BrowncreateLink(namespace:'api', controller:'upload', action:'post')
. Is the action in your controller that you want to link to namedpost
? Also, there isn't enough info in your question to know for sure but you may want to specify the HTTP method with something likecreateLink(namespace:'api', controller:'upload', action:'post', method: 'POST')
– Jeff Scott Brown