64 lines
1.9 KiB
PHP
64 lines
1.9 KiB
PHP
|
|
<?php
|
||
|
|
declare(strict_types=1);
|
||
|
|
|
||
|
|
namespace Phred\Http\Responses;
|
||
|
|
|
||
|
|
use Nyholm\Psr7\Factory\Psr17Factory;
|
||
|
|
use Phred\Http\Contracts\ApiResponseFactoryInterface;
|
||
|
|
use Psr\Http\Message\ResponseInterface;
|
||
|
|
|
||
|
|
final class JsonApiResponseFactory implements ApiResponseFactoryInterface
|
||
|
|
{
|
||
|
|
public function __construct(private Psr17Factory $psr17 = new Psr17Factory()) {}
|
||
|
|
|
||
|
|
public function ok(array $data = []): ResponseInterface
|
||
|
|
{
|
||
|
|
return $this->document(['data' => $data], 200);
|
||
|
|
}
|
||
|
|
|
||
|
|
public function created(array $data = [], ?string $location = null): ResponseInterface
|
||
|
|
{
|
||
|
|
$res = $this->document(['data' => $data], 201);
|
||
|
|
if ($location) {
|
||
|
|
$res = $res->withHeader('Location', $location);
|
||
|
|
}
|
||
|
|
return $res;
|
||
|
|
}
|
||
|
|
|
||
|
|
public function noContent(): ResponseInterface
|
||
|
|
{
|
||
|
|
// JSON:API allows 204 without body
|
||
|
|
return $this->psr17->createResponse(204);
|
||
|
|
}
|
||
|
|
|
||
|
|
public function error(int $status, string $title, ?string $detail = null, array $extra = []): ResponseInterface
|
||
|
|
{
|
||
|
|
$error = array_filter([
|
||
|
|
'status' => (string) $status,
|
||
|
|
'title' => $title,
|
||
|
|
'detail' => $detail,
|
||
|
|
], static fn($v) => $v !== null && $v !== '');
|
||
|
|
if (!empty($extra)) {
|
||
|
|
$error = array_merge($error, $extra);
|
||
|
|
}
|
||
|
|
return $this->document(['errors' => [$error]], $status);
|
||
|
|
}
|
||
|
|
|
||
|
|
public function fromArray(array $payload, int $status = 200): ResponseInterface
|
||
|
|
{
|
||
|
|
// Caller must ensure payload is a valid JSON:API document shape
|
||
|
|
return $this->document($payload, $status);
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* @param array<string,mixed> $doc
|
||
|
|
*/
|
||
|
|
private function document(array $doc, int $status): ResponseInterface
|
||
|
|
{
|
||
|
|
$res = $this->psr17->createResponse($status)
|
||
|
|
->withHeader('Content-Type', 'application/vnd.api+json');
|
||
|
|
$res->getBody()->write(json_encode($doc, JSON_UNESCAPED_SLASHES));
|
||
|
|
return $res;
|
||
|
|
}
|
||
|
|
}
|