REST

REST 是开放网络的基础概念。CakePHP 提供功能来构建应用程序,这些应用程序以低复杂性抽象和接口公开 REST API。

CakePHP 提供方法通过 HTTP 方法公开您的控制器操作,并根据内容类型协商序列化视图变量。内容类型协商允许应用程序的客户端发送具有序列化数据的请求,并通过 AcceptContent-Type 标头或 URL 扩展名接收具有序列化数据的响应。

入门

要开始将 REST API 添加到您的应用程序中,我们首先需要一个包含要作为 API 公开的操作的控制器。一个基本的控制器可能看起来像这样

// 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']);
    }
}

在我们的 RecipesController 中,我们有几个操作定义了创建、编辑、查看和删除食谱的逻辑。在我们的每个操作中,我们都使用 serialize 选项来告诉 CakePHP 在进行 API 响应时应序列化哪些视图变量。我们将使用 RESTful 路由 将我们的控制器连接到应用程序 URL。

// in config/routes.php
$routes->scope('/', function (RouteBuilder $routes): void {
    $routes->setExtensions(['json']);
    $routes->resources('Recipes');
});

这些路由将启用诸如 /recipes.json 之类的 URL 来返回 JSON 编码的响应。客户端还可以向 /recipes 发送带有 Content-Type: application/json 标头的请求。

编码响应数据

在上面的控制器中,我们定义了一个 viewClasses() 方法。此方法定义了您的控制器可用于内容协商的视图。我们包含了 CakePHP 的 JsonView,它支持基于 JSON 的响应。要了解有关它的更多信息以及基于 XML 的视图,请参阅 JSON 和 XML 视图。由 CakePHP 用于选择视图类来呈现 REST 响应。

接下来,我们有几个方法公开了创建、编辑、查看和删除食谱的基本逻辑。在我们的每个操作中,我们都使用 serialize 选项来告诉 CakePHP 在进行 API 响应时应序列化哪些视图变量。

如果我们想在将数据转换为 JSON 之前修改数据,我们不应该定义 serialize 选项,而应该使用模板文件。我们将在 templates/Recipes/json 中放置 RecipesController 的 REST 模板。

有关 CakePHP 响应协商功能的更多信息,请参阅 内容类型协商

解析请求主体

为编辑操作创建逻辑需要另一个步骤。因为我们的资源被序列化为 JSON,所以如果我们的请求也包含 JSON 表示,那将是符合人体工程学的。

在我们的 Application 类中,确保存在以下内容

$middlewareQueue->add(new BodyParserMiddleware());

此中间件将使用 content-type 标头来检测请求数据的格式并解析已启用的格式。默认情况下,仅 JSON 解析默认情况下启用。您可以通过启用 xml 构造函数选项来启用 XML 支持。当使用 Content-Typeapplication/json 的请求时,CakePHP 将解码请求数据并更新请求,以便 $request->getData() 包含已解析的主体。

如果您需要,还可以使用 BodyParserMiddleware::addParser() 为其他格式连接额外的反序列化器。