////
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements.  See the NOTICE file
distributed with this work for additional information
regarding copyright ownership.  The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License.  You may obtain a copy of the License at

https://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied.  See the License for the
specific language governing permissions and limitations
under the License.
////


==== Simple Variables


The previous section demonstrated how to map simple URLs with concrete "tokens". In URL mapping speak tokens are the sequence of characters between each slash, '/'. A concrete token is one which is well defined such as as `/product`. However, in many circumstances you don't know what the value of a particular token will be until runtime. In this case you can use variable placeholders within the URL for example:

[source,groovy]
----
static mappings = {
  "/product/$id"(controller: "product")
}
----

In this case by embedding a $id variable as the second token Grails will automatically map the second token into a parameter (available via the link:{controllersRef}params.html[params] object) called `id`. For example given the URL `/product/MacBook`, the following code will render "MacBook" to the response:

[source,groovy]
----
class ProductController {
     def index() { render params.id }
}
----

You can of course construct more complex examples of mappings. For example the traditional blog URL format could be mapped as follows:

[source,groovy]
----
static mappings = {
   "/$blog/$year/$month/$day/$id"(controller: "blog", action: "show")
}
----

The above mapping would let you do things like:

[source]
----
/graemerocher/2007/01/10/my_funky_blog_entry
----

The individual tokens in the URL would again be mapped into the link:{controllersRef}params.html[params] object with values available for `year`, `month`, `day`, `id` and so on.


==== Dynamic Controller and Action Names


Variables can also be used to dynamically construct the controller and action name. In fact the default Grails URL mappings use this technique:

[source,groovy]
----
static mappings = {
    "/$controller/$action?/$id?"()
}
----

Here the name of the controller, action and id are implicitly obtained from the variables `controller`, `action` and `id` embedded within the URL.

===== Wildcard Artefact Validation

By default, when URL mappings use wildcard variables like `$controller`, `$action`, or `$namespace`, Grails validates the captured values against registered controller artefacts. If a captured value does not correspond to a real controller, action, or namespace, the mapping is skipped and the next mapping is tried.

This enables patterns where a `$action` wildcard is followed by a fallback mapping:

[source,groovy]
----
group "/topics", {
    "/$action"(controller: 'topic')
    "/$id"(controller: 'topic', action: 'show')
}
----

With this configuration:

* `/topics/gallery` — "gallery" is validated as a real action on `TopicController`, so the `$action` mapping is used.
* `/topics/42` — "42" is not a valid action, so the `$action` mapping is skipped and the `$id` mapping handles the request, routing to the `show` action.

This validation applies to `$controller`, `$action`, and `$namespace` wildcards. Hardcoded values in mappings (e.g., `controller: 'topic'`) are never filtered — only wildcard-captured values are validated.

When a wildcard-captured action matches a real action on the controller, it takes priority over less-specific fallback mappings where the action is hardcoded. This means a `$action` mapping that resolves to a valid action will be preferred over a catch-all mapping such as `$id` with a hardcoded action, even if the fallback mapping sorts ahead of it.

More-specific mappings still win. Literal paths such as `/community` and explicit method-specific mappings such as `post "/invites"` are not displaced by wildcard controller/action matches.

To disable this behavior, set in `application.yml`:

[source,yaml]
----
grails:
    web:
        url:
            mapping:
                validateWildcards: false
----

You can also resolve the controller name and action name to execute dynamically using a closure:

[source,groovy]
----
static mappings = {
    "/$controller" {
        action = { params.goHere }
    }
}
----


==== Optional Variables


Another characteristic of the default mapping is the ability to append a ? at the end of a variable to make it an optional token. In a further example this technique could be applied to the blog URL mapping to have more flexible linking:

[source,groovy]
----
static mappings = {
    "/$blog/$year?/$month?/$day?/$id?"(controller:"blog", action:"show")
}
----

With this mapping all of these URLs would match with only the relevant parameters being populated in the link:{controllersRef}params.html[params] object:

----
/graemerocher/2007/01/10/my_funky_blog_entry
/graemerocher/2007/01/10
/graemerocher/2007/01
/graemerocher/2007
/graemerocher
----


==== Optional File Extensions


If you wish to capture the extension of a particular path, then a special case mapping exists:

[source,groovy]
----
"/$controller/$action?/$id?(.$format)?"()
----

By adding the `(.$format)?` mapping you can access the file extension using the `response.format` property in a controller:

[source,groovy]
----
def index() {
    render "extension is ${response.format}"
}
----


==== Arbitrary Variables


You can also pass arbitrary parameters from the URL mapping into the controller by just setting them in the block passed to the mapping:

[source,groovy]
----
"/holiday/win" {
     id = "Marrakech"
     year = 2007
}
----

This variables will be available within the link:{controllersRef}params.html[params] object passed to the controller.


==== Dynamically Resolved Variables


The hard coded arbitrary variables are useful, but sometimes you need to calculate the name of the variable based on runtime factors. This is also possible by assigning a block to the variable name:

[source,groovy]
----
"/holiday/win" {
     id = { params.id }
     isEligible = { session.user != null } // must be logged in
}
----

In the above case the code within the blocks is resolved when the URL is actually matched and hence can be used in combination with all sorts of logic.
