Skip to main content
Version: Next

Create custom route parameters

Although Marten has built-in support for common route parameters, it is also possible to implement your very own parameter types. This may be necessary if your routes have more complex matching requirements.

Defining a route parameter

In order to implement custom parameters, you need to subclass the Marten::Routing::Parameter::Base abstract class. Each parameter class is responsible for:

  • defining a Regex allowing to match the parameters in raw paths (which can be done by implementing a #regex method)
  • defining how the route parameter value should be deserialized (which can be done by implementing a #loads method)
  • defining how the route parameter value should serialized (which can be done by implementing a #dumps method)

The #regex method takes no arguments and must return a valid Regex object.

The #loads method takes the raw parameter (string) as argument and is expected to return the final Crystal object corresponding to the route parameter (this is the object that will be forwarded to the handler in the route parameters hash).

The #dumps method takes the final route parameter object as argument and must return the corresponding string representation. Note that this method can either return a string or nil: nil means that the passed value couldn't be serialized properly, which will make any URL reverse resolution fail with a Marten::Routing::Errors::NoReverseMatch error.

For example, a "year" (1000-2999) route parameter could be implemented as follows:

class YearParameter < Marten::Routing::Parameter::Base
def regex : Regex
/[12][0-9]{3}/
end

def loads(value : ::String) : UInt64
value.to_u64
end

def dumps(value) : Nil | ::String
if value.as?(UInt8 | UInt16 | UInt32 | UInt64)
value.to_s
elsif value.is_a?(Int8 | Int16 | Int32 | Int64) && [1000..2999].includes?(value)
value.to_s
else
nil
end
end
end

Registering route parameters

In order to be able to use custom route parameters in your route definitions, you must register them to Marten's global routing parameters registry.

To do so, you will have to call the Marten::Routing::Parameter#register method with the identifier of the parameter you wish to use in route path definitions, and the actual parameter class. For example:

Marten::Routing::Parameter.register(:year, YearParameter)

With the above registration, you could technically create the following route definition:

Marten.routes.draw do
path "/vintage/<vintage:year>", VintageHandler, name: "vintage"
end