The library casts a json-request to your object and casts your object to a json-response.
- Make an ApiRationObject, example SimpleModel
<?php
declare(strict_types=1);
namespace App;
use YaPro\ApiRationBundle\Marker\ApiRationObjectInterface;
class SimpleModel implements ApiRationObjectInterface
{
private string $varString;
private bool $varBoolean;
public function __construct(string $varString, bool $varBoolean) {
$this->varString = $varString;
$this->varBoolean = $varBoolean;
}
public function getVarString(): string
{
return $this->varString;
}
public function isVarBoolean(): bool
{
return $this->varBoolean;
}
}
- Use the SimpleModel in controller action (specify the namespace completely)
<?php
declare(strict_types=1);
namespace App\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Routing\Annotation\Route;
class AppController extends AbstractController
{
/**
* @Route("/api-json-test/simple-model")
*
* @param \App\SimpleModel $model
*
* @return SimpleModel
*/
public function getSimpleModel(SimpleModel $model, Request $request): SimpleModel
{
return $model;
}
}
- Make the curl request
curl -X GET "localhost/api-json-test/simple-model" -H 'Content-Type: application/json' -d'
{
"varString": "string",
"varBoolean": "true"
}
'
- Get the answer
{"varString":"string","varBoolean":true}
As you can see, any object which implements the ApiRationObjectInterface is automatically converted to json.
<?php
declare(strict_types=1);
namespace App\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\HttpFoundation\JsonResponse;
use YaPro\ApiRationBundle\Request\JsonRequest;
class AppController extends AbstractController
{
/**
* @Route("/search", methods={"POST"})
*
* @param JsonRequest $request
* @param ArticleRepository $articleRepository
*
* @return JsonResponse
*/
public function search(JsonRequest $request): JsonResponse
{
$userAddresses = $request->getArray(); // request: ["[email protected]", "[email protected]"]
// OR:
$myFieldValue = $request->getObject()->myField; // request: {"myField": "my value"}
return $this->json([]);
}
If you need to create a JsonLd response for the creation operation, try:
return new ResourceCreatedJsonLdResponse(
$article->getId(),
[
'title' => $article->getTitle(),
'text' => $article->getText(),
]
);
If you need to create a JsonLd response for an update operation, try ResourceUpdatedJsonLdResponse.
CollectionJsonLdResponse is automatically support pagination:
<?php
declare(strict_types=1);
namespace App\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Routing\Annotation\Route;
use YaPro\ApiRationBundle\Response\JsonLd\CollectionJsonLdResponse;
class AppController extends AbstractController
{
/**
* @Route("/list", methods={"GET"})
*/
public function list(Request $request, ArticleRepository $articleRepository, SerializerInterface $serializer)
{
$collection = $articleRepository->getList();
/*
function getList(): array {
return $this->createQueryBuilder('t')
->select('t')
->where('t.difficulty > 0')
->getQuery()
->getResult();
}
*/
$items = $serializer->normalize($collection, null, ['groups' => 'apiRead']);
return (new CollectionJsonLdResponse($request))->initData($items);
}
/**
* @Route("/search", methods={"GET"})
*
* @param Request $request
* @param ArticleRepository $articleRepository
*
* @return CollectionJsonLdResponse
*/
public function search(Request $request, ArticleRepository $articleRepository): CollectionJsonLdResponse
{
$response = new CollectionJsonLdResponse($request);
$searchValue = $request->query->get('searchValue', '');
if (empty($searchValue)) {
return $response;
}
$items = $this->getEntityManager()->getConnection()->fetchAll("
SELECT
id,
title
FROM Article
WHERE title LIKE :searchValue
ORDER BY createdAt DESC
LIMIT " . $response->getOffset() . ", " . $response->getLimit() . "
", [
'searchValue' => $searchValue,
]);
return $response->initData(
$items,
$this->getTotalItems()
);
}
}
Notice: symfony 6.3 is supports similar features, but the bundle supports more functionality, for example, responding to an invalid request by throwing a BadRequestException:
$message = 'Validation errors';
$errors = [
'field_name' => 'The name cannot contain a number',
'field_lastname' => [
'The name cannot contain a number',
'Name must be at least 2 characters long',
],
];
throw new BadRequestException($message, $errors);
and the client will receive the response with the status 400:
{
"message": "Validation errors",
"errors": [
{
"fieldName": "field_name",
"messages": [
"The name cannot contain a number"
]
},
{
"fieldName": "field_lastname",
"messages": [
"The name cannot contain a number",
"Name must be at least 2 characters long"
]
}
]
}
More examples.
Add as a requirement in your composer.json
file or run for prod:
composer require yapro/apiration-bundle laminas/laminas-code:3.4.1
Add as a requirement in your composer.json
file or run for prod:
composer require yapro/apiration-bundle
As dev:
composer require yapro/apiration-bundle dev-master
docker build -t yapro/apiration-bundle:latest -f ./Dockerfile ./
docker run --rm --user=$(id -u):$(id -g) --add-host=host.docker.internal:host-gateway -it --rm -v $(pwd):/app -w /app yapro/apiration-bundle:latest bash
cp -f composer.lock.php7 composer.lock
composer install -o
Debug tests:
PHP_IDE_CONFIG="serverName=common" \
XDEBUG_SESSION=common \
XDEBUG_MODE=debug \
XDEBUG_CONFIG="max_nesting_level=200 client_port=9003 client_host=host.docker.internal" \
vendor/bin/simple-phpunit --cache-result-file=/tmp/phpunit.cache -v --stderr --stop-on-incomplete --stop-on-defect \
--stop-on-failure --stop-on-warning --fail-on-warning --stop-on-risky --fail-on-risky --testsuite=Unit,Functional
If you need php8:
docker build -t yapro/apiration-bundle:latest --build-arg "PHP_VERSION=8" -f ./Dockerfile ./
cp -f composer.lock.php8 composer.lock
Cs-Fixer:
wget https://github.com/FriendsOfPHP/PHP-CS-Fixer/releases/download/v3.8.0/php-cs-fixer.phar && chmod +x ./php-cs-fixer.phar
./php-cs-fixer.phar fix --config=.php-cs-fixer.dist.php -v --using-cache=no --allow-risky=yes
Update phpmd rules:
wget https://github.com/phpmd/phpmd/releases/download/2.12.0/phpmd.phar && chmod +x ./phpmd.phar
./phpmd.phar . text phpmd.xml --exclude .github/workflows,vendor --strict --generate-baseline
YaPro\ApiRationBundle\Cors\CorsResolver:
tags:
- { name: kernel.event_subscriber }
If the library doesn't work, try to add the following lines to services.yml:
Symfony\Component\Serializer\Encoder\JsonDecode: ~
Symfony\Component\Serializer\Encoder\JsonEncode: ~