JSON API

Responses::json() zakóduje data do JSON a vrátí PSR-7 odpověď se zadaným HTTP statusem a content type.

Registrace endpointu

AppApiEndpointProvider registruje v ApiEndpointRegistry veřejné operace GET status a POST preview. ControllerAction::for() u každé určuje akci controlleru. Cesty zapsané zde ještě neobsahují prefix z Api.yaml; ten se přidá při sestavení rout.

app/Api/AppApiEndpointProvider.php
<?php

declare(strict_types=1);

namespace App\Api;

use App\Controllers\Api\PreviewController;
use App\Controllers\Api\StatusController;
use Lemonade\Framework\Api\Endpoint\ApiAccess;
use Lemonade\Framework\Api\Endpoint\ApiEndpointProviderInterface;
use Lemonade\Framework\Api\Endpoint\ApiEndpointRegistry;
use Lemonade\Framework\Routing\ControllerAction;

final class AppApiEndpointProvider implements ApiEndpointProviderInterface
{
    public function register(ApiEndpointRegistry $registry): void
    {
        $registry->get(
            path: '/app/status',
            controllerAction: ControllerAction::for(StatusController::class, 'show'),
            name: 'app.status',
            summary: 'Application status',
            description: 'Returns application availability.',
            access: ApiAccess::Public,
        );
        $registry->post(
            path: '/app/preview',
            controllerAction: ControllerAction::for(PreviewController::class, 'create'),
            name: 'app.preview',
            summary: 'Preview title',
            description: 'Returns a normalized title.',
            access: ApiAccess::Public,
        );
    }
}

Api.yaml zapíná API, nastavuje prefix /api a přidává právě uvedený endpoint provider. Po načtení modulu z Config.yaml budou výsledné cesty /api/app/status a /api/app/preview.

app/Config/Api.yaml
module: api
config:
  enabled: true
  prefix: /api
  endpoint_providers:
    - App\Api\AppApiEndpointProvider

Odpověď a status

StatusController přijímá Responses konstruktorem a show() vrací JSON tělo s klíčem data. Responses::json() vytvoří PSR-7 odpověď se statusem 200; jiný status, například 201 nebo 422, lze předat druhým argumentem.

StatusController.php
<?php

declare(strict_types=1);

namespace App\Controllers\Api;

use Lemonade\Framework\Http\Response\Responses;
use Psr\Http\Message\ResponseInterface;

final readonly class StatusController
{
    public function __construct(private Responses $responses) {}

    public function show(): ResponseInterface
    {
        return $this->responses->json(['data' => ['status' => 'ready']]);
    }
}

Čtení vstupu a chyby

PreviewController čte title z RequestData::jsonPayload() a odmítá hodnotu, která není neprázdným řetězcem, statusem 422. Platný titul ořízne a vrátí jako JSON 200; nic neukládá. jsonPayload() vrací prázdné pole i při neplatném JSON, takže pro odlišení této chyby od prázdného objektu je nutné tělo dekódovat a chybu ověřit zvlášť.

app/Controllers/Api/PreviewController.php
<?php

declare(strict_types=1);

namespace App\Controllers\Api;

use Lemonade\Framework\Core\Http\RequestData;
use Lemonade\Framework\Http\Response\Responses;
use Psr\Http\Message\ResponseInterface;

final readonly class PreviewController
{
    public function __construct(
        private RequestData $request,
        private Responses $responses,
    ) {}

    public function create(): ResponseInterface
    {
        $title = $this->request->jsonPayload()['title'] ?? null;
        if (!is_string($title) || trim($title) === '') {
            return $this->responses->json(['error' => 'Title is required'], 422);
        }

        return $this->responses->json(['title' => trim($title)], 200);
    }
}

Při prázdném nebo chybějícím title je toto JSON tělo chybové odpovědi. Číslo 422 je HTTP status nastavený controllerem, nikoli pole v JSON těle.

HTTP 422
{"error":"Title is required"}

Příkaz odešle prázdný JSON objekt na registrovaný POST endpoint. Právě kvůli chybějícímu title dostane odpověď HTTP 422 s předchozím tělem.

Terminal
curl -i -X POST http://localhost/api/app/preview \
  -H 'Content-Type: application/json' -d '{}'
Související dokumentaceVíce informací najdete v kapitole JSON API v dokumentaci.

← Všechny ukázky