Encodera

Спасибо, что читаете!

Пожертвуйте сайту, мы стараемся ради вас.

Оглавление

REST API

API — адреса сайта, которые отдают не страницы, а данные, обычно в формате JSON. Ими пользуются мобильные приложения и JavaScript. REST — договорённость о таких адресах: один адрес обозначает ресурс (статьи), а метод HTTP — действие над ним. В Laminas для этого есть готовый базовый контроллер.

Подготовка

В уроке об ответах в config/autoload/global.php уже включена стратегия ViewJsonStrategy — без неё JsonModel не превратится в ответ JSON.

Контроллер API

Создайте файл в папке контроллеров модуля:

// module/Blog/src/Controller/PostApiController.php
namespace Blog\Controller;
 
use Blog\Model\PostTable;
use Laminas\Mvc\Controller\AbstractRestfulController;
use Laminas\View\Model\JsonModel;
 
class PostApiController extends AbstractRestfulController
{
    public function __construct(private PostTable $posts) {}
 
    public function getList()
    {
        return new JsonModel(['data' => $this->posts->fetchLatest(20)]);
    }
}

Класс наследует AbstractRestfulController. В отличие от обычного контроллера здесь нет действий с окончанием Action: метод выбирается по методу HTTP.

Маршрут

Добавьте контроллер в controllers.factories с ReflectionBasedAbstractFactory и опишите маршрут в module/Blog/config/module.config.php:

// module/Blog/config/module.config.php, внутри 'routes'
'api-posts' => [
    'type' => Segment::class,
    'options' => [
        'route' => '/api/posts[/:id]',
        'constraints' => ['id' => '[0-9]+'],
        'defaults' => [
            'controller' => Controller\PostApiController::class,
        ],
    ],
],

Ключа action в маршруте нет — метод выбирает сам контроллер. Откройте /api/posts: браузер покажет JSON с ключом data и списком статей.

Какой метод вызывается

ЗапросМетод контроллера
GET /api/postsgetList()
GET /api/posts/5get($id)
POST /api/postscreate($data)
PUT /api/posts/5update($id, $data)
DELETE /api/posts/5delete($id)

Если метод не описан в вашем классе, контроллер ответит кодом 405 «метод не разрешён».

Одна запись

public function get($id)
{
    $post = $this->posts->find((int) $id);
 
    if ($post === null) {
        $this->getResponse()->setStatusCode(404);
 
        return new JsonModel(['error' => 'Статья не найдена']);
    }
 
    return new JsonModel(['data' => $post]);
}

Для несуществующей статьи клиент получит код 404 и сообщение об ошибке в JSON.

Создание и удаление

public function create($data)
{
    $post = new Post();
    $post->exchangeArray($data);
    $this->posts->save($post);
 
    $this->getResponse()->setStatusCode(201);
 
    return new JsonModel(['data' => $post]);
}
 
public function delete($id)
{
    $this->posts->delete((int) $id);
 
    $this->getResponse()->setStatusCode(204);
 
    return new JsonModel();
}

В $data приходит массив полей. Если клиент отправил тело в формате JSON с заголовком Content-Type: application/json, контроллер разберёт его сам. Код 201 означает «создано», 204 — «выполнено, тела ответа нет». Перед сохранением данные проверяют набором правил InputFilter из урока о проверке данных.

Проверка через curl

curl http://localhost:8080/api/posts/1
 
curl -X POST http://localhost:8080/api/posts \
  -H "Content-Type: application/json" \
  -d '{"title": "Статья из API", "body": "Текст статьи."}'

Первая команда напечатает статью с номером 1, вторая создаст новую и вернёт её вместе с присвоенным id.

Частая ошибка

API не защищён слушателем из урока о правах, если его маршрут не внесён в список закрытых: адрес DELETE /api/posts/5 удалит статью по запросу любого посетителя. Добавьте маршрут api-posts в проверку и для запросов, меняющих данные, отвечайте кодом 401 вместо перенаправления на страницу входа.

Спасибо, что читаете!

Пожертвуйте сайту, мы стараемся ради вас.