diff --git a/lib/private/AppFramework/Routing/RouteConfig.php b/lib/private/AppFramework/Routing/RouteConfig.php
index 70208725f4636cb32b9f1bb3c1c5457ec6d3fe7a..30cd4cea167c68a0c5dddd34b7495600b7942603 100644
--- a/lib/private/AppFramework/Routing/RouteConfig.php
+++ b/lib/private/AppFramework/Routing/RouteConfig.php
@@ -84,6 +84,9 @@ class RouteConfig {
 		// parse ocs simple routes
 		$this->processOCS($this->routes);
 
+		// parse ocs simple routes
+		$this->processOCSResources($this->routes);
+
 		$this->router->useCollection($oldCollection);
 	}
 
@@ -190,7 +193,58 @@ class RouteConfig {
 	 * For a given name and url restful routes are created:
 	 *  - index
 	 *  - show
-	 *  - new
+	 *  - create
+	 *  - update
+	 *  - destroy
+	 *
+	 * @param array $routes
+	 */
+	private function processOCSResources($routes)
+	{
+		// declaration of all restful actions
+		$actions = array(
+			array('name' => 'index', 'verb' => 'GET', 'on-collection' => true),
+			array('name' => 'show', 'verb' => 'GET'),
+			array('name' => 'create', 'verb' => 'POST', 'on-collection' => true),
+			array('name' => 'update', 'verb' => 'PUT'),
+			array('name' => 'destroy', 'verb' => 'DELETE'),
+		);
+
+		$resources = $routes['ocs-resources'] ?? [];
+		foreach ($resources as $resource => $config) {
+			$root = $config['root'] ?? '/apps/' . $this->appName;
+
+			// the url parameter used as id to the resource
+			foreach($actions as $action) {
+				$url = $root . $config['url'];
+				$method = $action['name'];
+				$verb = strtoupper($action['verb'] ?? 'GET');
+				$collectionAction = $action['on-collection'] ?? false;
+				if (!$collectionAction) {
+					$url .= '/{id}';
+				}
+				if (isset($action['url-postfix'])) {
+					$url .= '/' . $action['url-postfix'];
+				}
+
+				$controller = $resource;
+
+				$controllerName = $this->buildControllerName($controller);
+				$actionName = $this->buildActionName($method);
+
+				$routeName = 'ocs.' . $this->appName . '.' . strtolower($resource) . '.' . strtolower($method);
+
+				$this->router->create($routeName, $url)->method($verb)->action(
+					new RouteActionHandler($this->container, $controllerName, $actionName)
+				);
+			}
+		}
+	}
+
+	/**
+	 * For a given name and url restful routes are created:
+	 *  - index
+	 *  - show
 	 *  - create
 	 *  - update
 	 *  - destroy
diff --git a/tests/lib/AppFramework/Routing/RoutingTest.php b/tests/lib/AppFramework/Routing/RoutingTest.php
index 76533fff014084bca1a70672051a0027d2019424..fccece481ce6e0a0473defde7b01252b836c005b 100644
--- a/tests/lib/AppFramework/Routing/RoutingTest.php
+++ b/tests/lib/AppFramework/Routing/RoutingTest.php
@@ -6,6 +6,9 @@ use OC\AppFramework\DependencyInjection\DIContainer;
 use OC\AppFramework\Routing\RouteActionHandler;
 use OC\AppFramework\Routing\RouteConfig;
 use OCP\ILogger;
+use OCP\Route\IRouter;
+use PHPUnit\Framework\MockObject\MockObject;
+use OC\Route\Router;
 
 class RoutingTest extends \Test\TestCase
 {
@@ -179,6 +182,27 @@ class RoutingTest extends \Test\TestCase
 		$this->assertSimpleOCSRoute($routes, 'admin_folders.open_current', 'DELETE', '/apps/app1/folders/{folderId}/open', 'AdminFoldersController', 'openCurrent');
 	}
 
+	public function testOCSResource()
+	{
+		$routes = ['ocs-resources' => ['account' => ['url' => '/accounts']]];
+
+		$this->assertOCSResource($routes, 'account', '/apps/app1/accounts', 'AccountController', 'id');
+	}
+
+	public function testOCSResourceWithUnderScoreName()
+	{
+		$routes = ['ocs-resources' => ['admin_accounts' => ['url' => '/admin/accounts']]];
+
+		$this->assertOCSResource($routes, 'admin_accounts', '/apps/app1/admin/accounts', 'AdminAccountsController', 'id');
+	}
+
+	public function testOCSResourceWithRoot()
+	{
+		$routes = ['ocs-resources' => ['admin_accounts' => ['url' => '/admin/accounts', 'root' => '/core/endpoint']]];
+
+		$this->assertOCSResource($routes, 'admin_accounts', '/core/endpoint/admin/accounts', 'AdminAccountsController', 'id');
+	}
+
 	public function testResource()
 	{
 		$routes = array('resources' => array('account' => array('url' => '/accounts')));
@@ -277,6 +301,67 @@ class RoutingTest extends \Test\TestCase
 		$config->register();
 	}
 
+	/**
+	 * @param array $yaml
+	 * @param string $resourceName
+	 * @param string $url
+	 * @param string $controllerName
+	 * @param string $paramName
+	 */
+	private function assertOCSResource($yaml, $resourceName, $url, $controllerName, $paramName): void {
+		/** @var IRouter|MockObject $router */
+		$router = $this->getMockBuilder(Router::class)
+			->setMethods(['create'])
+			->setConstructorArgs([$this->getMockBuilder(ILogger::class)->getMock()])
+			->getMock();
+
+		// route mocks
+		$container = new DIContainer('app1');
+		$indexRoute = $this->mockRoute($container, 'GET', $controllerName, 'index');
+		$showRoute = $this->mockRoute($container, 'GET', $controllerName, 'show');
+		$createRoute = $this->mockRoute($container, 'POST', $controllerName, 'create');
+		$updateRoute = $this->mockRoute($container, 'PUT', $controllerName, 'update');
+		$destroyRoute = $this->mockRoute($container, 'DELETE', $controllerName, 'destroy');
+
+		$urlWithParam = $url . '/{' . $paramName . '}';
+
+		// we expect create to be called once:
+		$router
+			->expects($this->at(0))
+			->method('create')
+			->with($this->equalTo('ocs.app1.' . $resourceName . '.index'), $this->equalTo($url))
+			->willReturn($indexRoute);
+
+		$router
+			->expects($this->at(1))
+			->method('create')
+			->with($this->equalTo('ocs.app1.' . $resourceName . '.show'), $this->equalTo($urlWithParam))
+			->willReturn($showRoute);
+
+		$router
+			->expects($this->at(2))
+			->method('create')
+			->with($this->equalTo('ocs.app1.' . $resourceName . '.create'), $this->equalTo($url))
+			->willReturn($createRoute);
+
+		$router
+			->expects($this->at(3))
+			->method('create')
+			->with($this->equalTo('ocs.app1.' . $resourceName . '.update'), $this->equalTo($urlWithParam))
+			->willReturn($updateRoute);
+
+		$router
+			->expects($this->at(4))
+			->method('create')
+			->with($this->equalTo('ocs.app1.' . $resourceName . '.destroy'), $this->equalTo($urlWithParam))
+			->willReturn($destroyRoute);
+
+		// load route configuration
+		$config = new RouteConfig($container, $router, $yaml);
+
+		$config->register();
+	}
+
 	/**
 	 * @param string $resourceName
 	 * @param string $url