This document is for CakePHP's development version, which can be significantly different
from previous releases.
You may want to read
current stable release documentation instead.
REST is a foundational concept to the open web. CakePHP provides functionality to build applications that expose REST APIs with low complexity abstractions and interfaces.
CakePHP provides methods for exposing your controller actions via HTTP methods,
and serializing view variables based on content-type negotiation. Content-Type
negotiation allows clients of your application to send requests with serialize
data and receive responses with serialized data via the Accept and
Content-Type headers, or URL extensions.
To get started with adding a REST API to your application, we’ll first need a controller containing actions that we want to expose as an API. 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']);
}
}
In our RecipesController, we have several actions that define the logic
to create, edit, view and delete recipes. In each of our actions we’re using
the serialize option to tell CakePHP which view variables should be
serialized when making API responses. We’ll connect our controller to the
application URLs with RESTful Routing:
// in config/routes.php
$routes->scope('/', function (RouteBuilder $routes): void {
$routes->setExtensions(['json']);
$routes->resources('Recipes');
});
These routes will enable URLs like /recipes.json to return a JSON encoded
response. Clients could also make a request to /recipes with the
Content-Type: application/json header as well.
In the above controller, we’re defining a viewClasses() method. This method
defines which views your controller has available for content-negotitation.
We’re including CakePHP’s JsonView which enables JSON based responses. To
learn more about it and Xml based views see JSON and XML views. is
used by CakePHP to select a view class to render a REST response with.
Next, we have several methods that expose basic logic to create, edit, view and
delete recipes. In each of our actions we’re using the serialize option to
tell CakePHP which view variables should be serialized when making API
responses.
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 would place
the REST templates for our RecipesController inside templates/Recipes/json.
See the Content Type Negotiation for more information on how CakePHP’s response negotiation functionality.
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. When a request is made with a Content-Type of
application/json, CakePHP will decode the request data and update the
request so that $request->getData() contains the parsed body.
You can also wire in additional deserializers for alternate formats if you
need them, using BodyParserMiddleware::addParser().