Many newer application programmers are realizing the need to open their core functionality to a greater audience. Providing unfettered access to your core API can help get your platform accepted, and allows for mashups and integration with other systems.
While other solutions exist, REST is a great way to provide access to the logic you’ve created in your application. It’s simple, usually XML-based (we’re talking simple XML, nothing like a SOAP envelope), and depends on HTTP headers for direction. Exposing an API via REST in CakePHP is simple.
The fastest way to get up and running with REST is to add a few lines to setup resource routes in your config/routes.php file.
Once the router has been set up to map REST requests to certain controller actions, we can move on to creating the logic in our controller actions. A basic controller might look something like this:
// src/Controller/RecipesController.php
use Cake\View\JsonView;
class RecipesController extends AppController
{
public function viewClasses(): array
{
return [JsonView::class];
}
public function index()
{
$recipes = $this->Recipes->find('all')->all();
$this->set('recipes', $recipes);
$this->viewBuilder()->setOption('serialize', ['recipes']);
}
public function view($id)
{
$recipe = $this->Recipes->get($id);
$this->set('recipe', $recipe);
$this->viewBuilder()->setOption('serialize', ['recipe']);
}
public function add()
{
$this->request->allowMethod(['post', 'put']);
$recipe = $this->Recipes->newEntity($this->request->getData());
if ($this->Recipes->save($recipe)) {
$message = 'Saved';
} else {
$message = 'Error';
}
$this->set([
'message' => $message,
'recipe' => $recipe,
]);
$this->viewBuilder()->setOption('serialize', ['recipe', 'message']);
}
public function edit($id)
{
$this->request->allowMethod(['patch', 'post', 'put']);
$recipe = $this->Recipes->get($id);
$recipe = $this->Recipes->patchEntity($recipe, $this->request->getData());
if ($this->Recipes->save($recipe)) {
$message = 'Saved';
} else {
$message = 'Error';
}
$this->set([
'message' => $message,
'recipe' => $recipe,
]);
$this->viewBuilder()->setOption('serialize', ['recipe', 'message']);
}
public function delete($id)
{
$this->request->allowMethod(['delete']);
$recipe = $this->Recipes->get($id);
$message = 'Deleted';
if (!$this->Recipes->delete($recipe)) {
$message = 'Error';
}
$this->set('message', $message);
$this->viewBuilder()->setOption('serialize', ['message']);
}
}
RESTful controllers often use parsed extensions to serve up different views
based on different kinds of requests. We’re defining the content-type based
views we support in this controller. We’re including CakePHP’s JsonView
. To
learn more about it and Xml based views see JSON and XML views. By
using JsonView
we can define a serialize
option. This option
is used to define which view variables JsonView
should serialize into JSON.
If we wanted to modify the data before it is converted into JSON we should not
define the serialize
option, and instead use template files. We place
the REST views for our RecipesController inside templates/Recipes/json.
Creating the logic for the edit action requires another step. Because our resources are serialized as JSON it would be ergonomic if our requests also contained the JSON representation.
In our Application
class ensure the following is present:
$middlewareQueue->add(new BodyParserMiddleware());
This middleware will use the content-type
header to detect the format of
request data and parse enabled formats. By default only JSON
parsing is
enabled by default. You can enable XML support by enabling the xml
constructor option.
Typically REST applications not only output content in alternate data formats,
but also accept data in different formats. In CakePHP, the
BodyParserMiddleware
helps facilitate this. By default,
it will decode any incoming JSON/XML input data for POST/PUT requests
and supply the array version of that data in $this->request->getData()
.
You can also wire in additional deserializers for alternate formats if you
need them, using BodyParserMiddleware::addParser()
.
CakePHP’s Router lets you connect RESTful resource routes with a fluent interface. See the section on RESTful Routing for more information.