Routing

Routes map a URL and a method to a controller method. Routes are defined inside :file:`appinfo/routes.php` by returning them as an array:

<?php
return [
    'routes' => [
        ['name' => 'page#index', 'url' => '/', 'verb' => 'GET'],
    ],
];
#[FrontpageRoute(verb: 'GET', url: '/')]

The route array contains the following parts:

OCS routes

Registering of OCS routes requires to use a :ref:`corresponding controller<ocscontroller>`. Additionally, the route must be configured to be an OCS route in the router. To do so, you use the ocs key in the routes.php file instead of the key routes. The rest of the structure is the same.

You can of course have both index.php and OCS routes.

<?php
return [
    'routes' => [
        ['name' => 'page#index', 'url' => '/', 'verb' => 'GET'],
    ],
    'ocs' => [
        ['name' => 'api#data', 'url' => '/v1/data', 'verb' => 'GET'],
    ],
];

The prefix for OCS routes is /ocs/v2.php/apps/<APPNAME>/. So, the configured URL for the OCS endpoint in the example would be <server>/ocs/v2.php/apps/<APPNAME>/v1/data.

Extracting values from the URL

It is possible to extract values from the URL to allow RESTful URL design. To extract a value, you have to wrap it inside curly braces:

<?php

// Request: GET /index.php/apps/myapp/authors/3

// appinfo/routes.php
['name' => 'author#show', 'url' => '/authors/{id}', 'verb' => 'GET'],

// controller/authorcontroller.php
class AuthorController {
    public function show(string $id): Response {
        // $id is '3'
    }
}

The identifier used inside the route is being passed into controller method by reflecting the method parameters. So basically if you want to get the value {id} in your method, you need to add $id to your method parameters.

Matching subURLs

Sometimes it is needed to match more than one URL fragment. An example would be to match a request for all URLs that start with OPTIONS /index.php/apps/myapp/api. To do this, use the requirements parameter in your route which is an array containing pairs of 'key' => 'regex':

<?php

// Request: OPTIONS /index.php/apps/myapp/api/my/route

// appinfo/routes.php
array('name' => 'author_api#cors', 'url' => '/api/{path}', 'verb' => 'OPTIONS',
      'requirements' => array('path' => '.+')),

// controller/authorapicontroller.php
class AuthorApiController {
    public function cors(string $path): Response {
        // $path will be 'my/route'
    }
}

Default values for subURL

Apart from matching requirements, a subURL may also have a default value. Say you want to support pagination (a 'page' parameter) for your /posts subURL that displays posts entries list. You may set a default value for the 'page' parameter, that will be used if not already set in the URL. Use the defaults parameter in your route which is an array containing pairs of 'urlparameter' => 'defaultvalue':

<?php

// Request: GET /index.php/app/myapp/post

// appinfo/routes.php
array(
    'name'     => 'post#index',
    'url'      => '/post/{page}',
    'verb'     => 'GET',
    'defaults' => array('page' => 1) // this allows same URL as /index.php/myapp/post/1
),

// controller/postcontroller.php
class PostController {
    public function index(int $page = 1): Response {
        // $page will be 1
    }
}

Registering resources

When dealing with resources, writing routes can become quite repetitive since most of the time routes for the following tasks are needed:

To prevent repetition, it's possible to define resources. The following routes:

<?php
return [
    'routes' => [
        ['name' => 'author#index', 'url' => '/authors', 'verb' => 'GET'],
        ['name' => 'author#show', 'url' => '/authors/{id}', 'verb' => 'GET'],
        ['name' => 'author#create', 'url' => '/authors', 'verb' => 'POST'],
        ['name' => 'author#update', 'url' => '/authors/{id}', 'verb' => 'PUT'],
        ['name' => 'author#destroy', 'url' => '/authors/{id}', 'verb' => 'DELETE'],
        // your other routes here
    ],
];

can be abbreviated by using the resources key:

<?php
return [
    'resources' => [
        'author' => ['url' => '/authors'],
    ],
    'routes' => [
        // your other routes here
    ],
];

Using the URLGenerator

Sometimes it is useful to turn a route into a URL to make the code independent from the URL design or to generate a URL for an image in img/. Inside the PageController the URL generator can be injected by adding it to the constructor, which will allow to use it to generate a URL for a redirect. For more details on that see the :ref:`dependency-injection` reference.

<?php
namespace OCA\MyApp\Controller;

use \OCP\IRequest;
use \OCP\IURLGenerator;
use \OCP\AppFramework\Controller;
use \OCP\AppFramework\Http\RedirectResponse;

class PageController extends Controller {

    private $urlGenerator;

    public function __construct(string $appName, IRequest $request,
                                IURLGenerator $urlGenerator) {
        parent::__construct($appName, $request);
        $this->urlGenerator = $urlGenerator;
    }

    /**
     * Redirects to /apps/news/myapp/authors/3
     */
    public function redirect(): RedirectResponse {
        // route name: author_api#do_something
        // route url: /apps/news/myapp/authors/{id}

        // # needs to be replaced with a . due to limitations and prefixed
        // with your app id
        $route = 'myapp.author_api.do_something';
        $parameters = ['id' => 3];

        $url = $this->urlGenerator->linkToRoute($route, $parameters);

        return new RedirectResponse($url);
    }
}

URLGenerator is case sensitive, so appName must match exactly the name you use in :doc:`configuration <../basics/storage/configuration>`. If you use a CamelCase name as myCamelCaseApp,

<?php
$route = 'myCamelCaseApp.author_api.do_something';

Console commands

Two occ commands help inspect and debug the routing table:

router
 router:list   list routes, optionally filtered by app
 router:match  match a URL path to a route

router:list

List all registered routes. Optionally filter to one or more apps:

sudo -E -u www-data php occ router:list
sudo -E -u www-data php occ router:list myapp

Use --ocs to show only OCS API routes, or --index to show only index.php routes:

sudo -E -u www-data php occ router:list --ocs
sudo -E -u www-data php occ router:list myapp --index

router:match

Match a URL path against the routing table and show which route and controller it resolves to. Useful for debugging why a request is landing in the wrong place:

sudo -E -u www-data php occ router:match /apps/myapp/authors/3

Use --method to match against a specific HTTP verb (default: GET):

sudo -E -u www-data php occ router:match /apps/myapp/authors/3 --method=POST