5

So for instance, say i have an API on a webapp, and i wish to use the same controllers and actions in the API as the rest of the webapp.

In my urlmappings file i have

"/api/$version/$apiKey/$controller/$acion/$id?"

and i also have a mapping like this:

"/blog/$year/$month/$day/$action" {
   controller = 'blog'
 }

Now the question is, can i somehow prefix the api urlmapping to the blog urlmapping so i can benefit from the $year, $month, $day variables? in such a way that a GET request to the following url would be valid:

GET /api/0.1/bs23mk4m2n4k/blog/2001/01/05/list

or am i forced to do the following request instead?

GET /api/0.1/bs23mk4m2n4k/blog/list?year=2004&month=01&day=05

Need help from an urlmappings GURU or a groovy runtime urlmappings maniuplation WIZARD :)

I want a solution that can reuse existing non-api urmappings, instead of having to redeclare them with the api path as a prefix.

netbrain
  • 9,194
  • 6
  • 42
  • 68

3 Answers3

3

You could have an ApiController strip off the api parameters, then redirect to the blog controller. For example:

"/api/$version/$apiKey/$rest**" {
     controller:'api'
     action:'default'
}


import org.codehaus.groovy.grails.web.util.WebUtils
class ApiController {
    def grailsUrlMappingsHolder

    def default = {
        // validate apiKey, etc
        WebUtils.forwardRequestForUrlMappingInfo(request, response, grailsUrlMappingsHolder.match("/${params.rest}"))
    }
}

The API controller has access to the version and apiKey params, and passes on the rest of the params to be processed by the blog controller's UrlMapping.

ataylor
  • 64,891
  • 24
  • 161
  • 189
  • this will cause a 302 redirect on all api calls :( not a good thing... but it will however work... – netbrain May 12 '11 at 19:42
  • 1
    Updated my answer to do an internal forward rather than a 302 redirect. – ataylor May 12 '11 at 20:29
  • Looks good, i will test it out. Would however be best if i could keep the additional class ApiController out of the picture aswell as the forward statement. But this is a definite solution! thanks! – netbrain May 13 '11 at 09:46
  • You wouldn't happen to know why filters are run twice when doing an internal forward. is this expected behaviour? – netbrain May 31 '11 at 17:48
0

I think you want to use embedded variables. Check the url mapping reference: http://grails.org/doc/latest/guide/single.html#6.4 URL Mappings

just add the following mapping:

static mappings = {
   "/api/$version/$apiKey/$controller/$year/$month/$day/$action"()
} 

now you can use this url for example:

http://localhost:8080/api/0.1/bs23mk4m2n4k/blog/2001/01/05/list

now you get redirected to the list action in the blog controller. there you can use params to show the parameters from the url (as defined in the mapping).

ex.

params.version
mjspier
  • 6,386
  • 5
  • 33
  • 43
  • "I want a solution that can reuse existing non-api urmappings, instead of having to redeclare them with the api path as a prefix." – netbrain May 12 '11 at 19:41
  • 1
    ok. missed this in your question. but why is it a problem to declare this mapping also? what is the benefit to use the existing mappings? – mjspier May 12 '11 at 22:32
  • but you have two different url patterns so two mappings are needed. they are not "identical". How many url mappings did you declare then. Maybe I get the problem when you post more of your url mapping. – mjspier May 13 '11 at 09:08
  • Look at ataylors answer. His answer does exactly what i want. With his solution both the /api urlmapping AND the "normal" mapping is executed, w/o having to declare any more /api urlmappings.. The only thing negative with his solution is that he is using a forward() call, which i have had my differences with in the past. What i originally wanted was for the urlmappings to be smart and understand that the /api urlmapping should be prefixed on all non-api urlmappings effectively creating what you have described in your solution. However, this shouldn't have to be done manually. – netbrain May 13 '11 at 09:44
-1

I had somewhat the same problem, solved it using named url mapping: http://www.grails.org/doc/latest/guide/6.%20The%20Web%20Layer.html#6.4.9%20Named%20URL%20Mappings

Hope this helps!

in urlMapping:

name blogWithYear:"/api/$version/$apiKey/$controller/$year/$month/$day":{
controller = 'blog'
action = 'youraction'
}

<g:link mapping="blogWithYear" params="[$version:'0.1', ....., '$year: 2011']">
Show blog
</g:link>

With g:link you can now compile the url however you want, adding parameters.

BadSkillz
  • 1,993
  • 19
  • 37