diff --git a/src/Controller.ts b/src/Controller.ts
index abdd228..7a26ad6 100644
--- a/src/Controller.ts
+++ b/src/Controller.ts
@@ -9,6 +9,9 @@ import Middleware, {MiddlewareType} from "./Middleware";
 import Application from "./Application";
 
 export default abstract class Controller {
+    /**
+     * TODO: this should not be static, it should actually be bound to an app instance.
+     */
     private static readonly routes: { [p: string]: string | undefined } = {};
 
     public static route(
@@ -20,11 +23,12 @@ export default abstract class Controller {
         let path = this.routes[route];
         if (path === undefined) throw new Error(`Unknown route for name ${route}.`);
 
+        const regExp = this.getRouteParamRegExp('[a-zA-Z0-9_-]+', 'g');
         if (typeof params === 'string' || typeof params === 'number') {
-            path = path.replace(/:[a-zA-Z_-]+\??/g, '' + params);
+            path = path.replace(regExp, '' + params);
         } else if (Array.isArray(params)) {
             let i = 0;
-            for (const match of path.matchAll(/:[a-zA-Z_-]+(\(.*\))?\??/g)) {
+            for (const match of path.matchAll(regExp)) {
                 if (match.length > 0) {
                     path = path.replace(match[0], typeof params[i] !== 'undefined' ? params[i] : '');
                 }
@@ -33,7 +37,7 @@ export default abstract class Controller {
             path = path.replace(/\/+/g, '/');
         } else {
             for (const key of Object.keys(params)) {
-                path = path.replace(new RegExp(`:${key}\\??`), params[key]);
+                path = path.replace(this.getRouteParamRegExp(key), params[key].toString());
             }
         }
 
@@ -41,6 +45,10 @@ export default abstract class Controller {
         return `${absolute ? config.get<string>('public_url') : ''}${path}` + (queryStr.length > 0 ? '?' + queryStr : '');
     }
 
+    private static getRouteParamRegExp(key: string, flags?: string): RegExp {
+        return new RegExp(`:${key}(\\(.+?\\))?\\??`, flags);
+    }
+
     private readonly router: Router = express.Router();
     private readonly fileUploadFormRouter: Router = express.Router();
     private app?: Application;
@@ -194,4 +202,4 @@ export default abstract class Controller {
     }
 }
 
-export type RouteParams = { [p: string]: string } | string[] | string | number;
+export type RouteParams = { [p: string]: string | number } | string[] | string | number;
diff --git a/test/Controller.test.ts b/test/Controller.test.ts
new file mode 100644
index 0000000..e296a68
--- /dev/null
+++ b/test/Controller.test.ts
@@ -0,0 +1,35 @@
+import Controller from "../src/Controller";
+
+describe('Controller.route()', () => {
+    new class extends Controller {
+        public routes(): void {
+            const emptyHandler = () => {
+                //
+            };
+            this.get('/test/no-param', emptyHandler, 'test.no-param');
+            this.get('/test/no-param/', emptyHandler, 'test.no-param-slash');
+            this.get('/test/one-param/:param', emptyHandler, 'test.one-param');
+            this.get('/test/two-params/:param1/:param2', emptyHandler, 'test.two-params');
+            this.get('/test/paginated/:page([0-9]+)?', emptyHandler, 'test.paginated');
+            this.get('/test/slug/:slug([a-zA-Z0-9]+)?', emptyHandler, 'test.slug');
+        }
+    }().setupRoutes();
+
+    test('Empty params', () => {
+        expect(Controller.route('test.no-param')).toBe('/test/no-param');
+        expect(Controller.route('test.no-param-slash')).toBe('/test/no-param/');
+        expect(Controller.route('test.one-param')).toBe('/test/one-param/');
+        expect(Controller.route('test.two-params')).toBe('/test/two-params/');
+        expect(Controller.route('test.paginated')).toBe('/test/paginated/');
+        expect(Controller.route('test.slug')).toBe('/test/slug/');
+    });
+
+    test('Populated params', () => {
+        expect(Controller.route('test.no-param')).toBe('/test/no-param');
+        expect(Controller.route('test.no-param-slash')).toBe('/test/no-param/');
+        expect(Controller.route('test.one-param', {param: 'value'})).toBe('/test/one-param/value');
+        expect(Controller.route('test.two-params', {param1: 'value1', param2: 'value2'})).toBe('/test/two-params/value1/value2');
+        expect(Controller.route('test.paginated', {page: 5})).toBe('/test/paginated/5');
+        expect(Controller.route('test.slug', {slug: 'abc'})).toBe('/test/slug/abc');
+    });
+});