A year ago csavelief7092 asked how to do this and I gave a response here. It is not the best solution and I’ve come across a better way to solve this. I’ve been reading on resource controllers and that is Laravel’s way of building RESTful APIs. So, I tried the same in OctoberCMS but realised that controllers work a little differently here. This guide should help those who want to build RESTful APIs.
So you need to scaffold a plugin for the REST service (or use existing plugins by extending it and adding the RESTful stuff). Make a routes.php. Here’s a sample:
<?php
Route::group(['prefix' => 'api/v1'], function () {
Route::resource('someroute', 'Acme\User\Controllers\MyController');
});
And this would be accessible from YOUR_URL/api/v1/someroute. Based on the HTTP request verb different actions would be called i.e. index, create, store, etc. You can see the list in the table here. The easy way of doing this is to create a controller MyController which extends Illuminate\Routing\Controller like this:
Contents of FooController.php (I create this in the usual plugin controller folder, you can create in separate folder if you want to)
<?php namespace Acme\Plugin\Controllers;
use Illuminate\Routing\Controller;
/**
* Sample Resourceful Test Controller
*/
class FooController extends Controller
{
public function index()
{
// Replace with logic to return the model data
return 'bar (index)';
}
public function store()
{
// Replace with logic to store/create the model. use post(‘varname’) to get values.
return 'bar (store)';
}
}
The route to add in the Route group for this is:
Route::resource('foo', 'Acme\Plugin\Controllers\FooController');
And this works perfectly well, you can write separate controllers for API classes. But I wanted to re-use OctoberCMS’s existing controller functions i.e. the Backend Controllers to add the RESTful components. So here’s what I did…
So assuming I scaffolded a plugin controller called Foo using php artisan create:controller Acme.Plugin Foo then inside Foo.php I tried adding index() but that broke the backend ListController. So, I added a few functions to enable the existing controller to allow RESTful API actions:
<?php namespace Acme\Plugin\Controllers;
use BackendMenu;
use Backend\Classes\Controller;
/**
* Foo Back-end Controller
*/
class Foo extends Controller
{
public $implement = [
'Backend.Behaviors.FormController',
'Backend.Behaviors.ListController'
];
public $formConfig = 'config_form.yaml';
public $listConfig = 'config_list.yaml';
public function __construct()
{
parent::__construct();
BackendMenu::setContext('Acme.Plugin', 'plugin', 'foo');
}
public function apiIndex()
{
return 'bar (index)';
}
public function apiFoo()
{
return 'bar (foo)';
}
/* Functions to allow RESTful actions */
public static function getAfterFilters() {return [];}
public static function getBeforeFilters() {return [];}
public static function getMiddleware() {return [];}
public function callAction($method, $parameters=false) {
$action = 'api' . ucfirst($method);
if (method_exists($this, $action) && is_callable(array($this, $action)))
{
return call_user_func_array(array($this, $action), $parameters);
} else {
return response()->json([
'message' => 'Not Found',
], 404);
}
}
}
So now I’m able to define the routes.php in the same way and at the same time allow using the existing controllers to build RESTful components to them. This is useful because for most use cases I would only be delivering the same models that are accessible to backend users thro’ backend controllers to my mobile users too (or any service that consumes the RESTful API). The only difference would be the level of access I’d give to the users on what they can view, edit or delete and these apiAction calls help solve that purpose without disturbing the existing backend controller’s actions.
You may have noticed that I’ve added an Foo action in the list even though it’s not a standard RESTful action that laravel provides. Sometimes, you might need custom actions so to do that you just have to add that action in the routes file before adding the Route::resource function. Like this…
Route::get(‘foo/foo', ‘Acme\Plugin\Controllers\Foo@foo');
Route::resource(‘foo', ‘Acme\ Plugin\Controllers\Foo');
So, now I’ve defined that foo action is accessible when the request comes with the GET HTTP verb and the second line does the usual i.e. gives access to the standard HTTP RESTful resource verbs that Laravel provides.
I hope this guide is accurate. For example, I am unsure about the Functions to allow RESTful actions as to whether it affects the backend ListController or FormController in any way but I hope not. I think it may be a good idea to add a RestController backend behaviour as public $implement = ['Backend.Behaviors.RestController']; in OctoberCMS core that automatically adds the functionality I just described (it could work in a way that it takes all functions that start with api as RESTful actions) so I don’t need to paste these functions in each controller which I wish to expose as a RESTful one. Hope the guide helps, do comment if you have corrections or suggestions.