mirror of
https://gitlab.com/Chill-Projet/chill-bundles.git
synced 2025-06-07 18:44:08 +00:00
documentation for api
This commit is contained in:
parent
e7985ea52f
commit
f880598052
353
docs/source/development/api.rst
Normal file
353
docs/source/development/api.rst
Normal file
@ -0,0 +1,353 @@
|
|||||||
|
.. Copyright (C) 2014 Champs Libres Cooperative SCRLFS
|
||||||
|
Permission is granted to copy, distribute and/or modify this document
|
||||||
|
under the terms of the GNU Free Documentation License, Version 1.3
|
||||||
|
or any later version published by the Free Software Foundation;
|
||||||
|
with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts.
|
||||||
|
A copy of the license is included in the section entitled "GNU
|
||||||
|
Free Documentation License".
|
||||||
|
|
||||||
|
.. _api
|
||||||
|
|
||||||
|
API
|
||||||
|
###
|
||||||
|
|
||||||
|
Chill provides a basic framework to build REST api.
|
||||||
|
|
||||||
|
Configure a route
|
||||||
|
=================
|
||||||
|
|
||||||
|
Follow those steps to build a REST api:
|
||||||
|
|
||||||
|
1. Create your model;
|
||||||
|
2. Configure the API;
|
||||||
|
|
||||||
|
You can also:
|
||||||
|
|
||||||
|
* hook into the controller to customize some steps;
|
||||||
|
* add more route and steps
|
||||||
|
|
||||||
|
.. read-also::
|
||||||
|
|
||||||
|
* `How to use annotation to configure serialization <https://symfony.com/doc/current/serializer.html>`_
|
||||||
|
* `How to create your custom normalizer <https://symfony.com/doc/current/serializer/custom_normalizer.html>`_
|
||||||
|
|
||||||
|
Auto-loading the routes
|
||||||
|
***********************
|
||||||
|
|
||||||
|
Ensure that those lines are present in your file `app/config/routing.yml`:
|
||||||
|
|
||||||
|
|
||||||
|
.. code-block:: yaml
|
||||||
|
|
||||||
|
chill_cruds:
|
||||||
|
resource: 'chill_main_crud_route_loader:load'
|
||||||
|
type: service
|
||||||
|
|
||||||
|
|
||||||
|
Create your model
|
||||||
|
*****************
|
||||||
|
|
||||||
|
Create your model on the usual way:
|
||||||
|
|
||||||
|
.. code-block:: php
|
||||||
|
|
||||||
|
namespace Chill\PersonBundle\Entity\AccompanyingPeriod;
|
||||||
|
|
||||||
|
use Chill\PersonBundle\Entity\AccompanyingPeriod\OriginRepository;
|
||||||
|
use Doctrine\ORM\Mapping as ORM;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ORM\Entity(repositoryClass=OriginRepository::class)
|
||||||
|
* @ORM\Table(name="chill_person_accompanying_period_origin")
|
||||||
|
*/
|
||||||
|
class Origin
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @ORM\Id
|
||||||
|
* @ORM\GeneratedValue
|
||||||
|
* @ORM\Column(type="integer")
|
||||||
|
*/
|
||||||
|
private $id;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ORM\Column(type="json")
|
||||||
|
*/
|
||||||
|
private $label;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ORM\Column(type="date_immutable", nullable=true)
|
||||||
|
*/
|
||||||
|
private $noActiveAfter;
|
||||||
|
|
||||||
|
// .. getters and setters
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Configure api
|
||||||
|
*************
|
||||||
|
|
||||||
|
Configure the api using Yaml (see the full configuration below):
|
||||||
|
|
||||||
|
.. code-block:: yaml
|
||||||
|
|
||||||
|
# config/packages/chill_main.yaml
|
||||||
|
chill_main:
|
||||||
|
apis:
|
||||||
|
accompanying_period_origin:
|
||||||
|
base_path: '/api/1.0/person/accompanying-period/origin'
|
||||||
|
class: 'Chill\PersonBundle\Entity\AccompanyingPeriod\Origin'
|
||||||
|
name: accompanying_period_origin
|
||||||
|
base_role: 'ROLE_USER'
|
||||||
|
actions:
|
||||||
|
_index:
|
||||||
|
methods:
|
||||||
|
GET: true
|
||||||
|
HEAD: true
|
||||||
|
_entity:
|
||||||
|
methods:
|
||||||
|
GET: true
|
||||||
|
HEAD: true
|
||||||
|
|
||||||
|
The :code:`_index` and :code:`_entity` action
|
||||||
|
=============================================
|
||||||
|
|
||||||
|
The :code:`_index` and :code:`_entity` action are default actions:
|
||||||
|
|
||||||
|
* they will call a specific method in the default controller;
|
||||||
|
* they will generate defined routes:
|
||||||
|
|
||||||
|
Index:
|
||||||
|
Name: :code:`chill_api_single_accompanying_period_origin__index`
|
||||||
|
|
||||||
|
Path: :code:`/api/1.0/person/accompanying-period/origin.{_format}`
|
||||||
|
|
||||||
|
Entity:
|
||||||
|
Name: :code:`chill_api_single_accompanying_period_origin__index`
|
||||||
|
|
||||||
|
Path: :code:`/api/1.0/person/accompanying-period/origin.{_format}`
|
||||||
|
|
||||||
|
Role
|
||||||
|
====
|
||||||
|
|
||||||
|
By default, the key `base_role` is used to check ACL. Take care of creating the :code:`Voter` required to take that into account.
|
||||||
|
|
||||||
|
For index action, the role will be called with :code:`NULL` as :code:`$subject`. The retrieved entity will be the subject for single queries.
|
||||||
|
|
||||||
|
You can also define a role for each method:
|
||||||
|
|
||||||
|
.. code-block:: yaml
|
||||||
|
|
||||||
|
# config/packages/chill_main.yaml
|
||||||
|
chill_main:
|
||||||
|
apis:
|
||||||
|
accompanying_period_origin:
|
||||||
|
base_path: '/api/1.0/person/bla/bla'
|
||||||
|
class: 'Chill\PersonBundle\Entity\Blah'
|
||||||
|
name: bla
|
||||||
|
actions:
|
||||||
|
_entity:
|
||||||
|
methods:
|
||||||
|
GET: true
|
||||||
|
HEAD: true
|
||||||
|
roles:
|
||||||
|
GET: MY_ROLE_SEE
|
||||||
|
HEAD: MY ROLE_SEE
|
||||||
|
|
||||||
|
Customize the controller
|
||||||
|
========================
|
||||||
|
|
||||||
|
You can customize the controller by hooking into the default actions. Take care of extending :code:`Chill\MainBundle\CRUD\Controller\ApiController`.
|
||||||
|
|
||||||
|
|
||||||
|
.. code-block:: php
|
||||||
|
|
||||||
|
|
||||||
|
namespace Chill\PersonBundle\Controller;
|
||||||
|
|
||||||
|
use Chill\MainBundle\CRUD\Controller\ApiController;
|
||||||
|
use Symfony\Component\HttpFoundation\Request;
|
||||||
|
use Symfony\Component\HttpFoundation\Response;
|
||||||
|
|
||||||
|
class OpeningApiController extends ApiController
|
||||||
|
{
|
||||||
|
protected function customizeQuery(string $action, Request $request, $qb): void
|
||||||
|
{
|
||||||
|
$qb->where($qb->expr()->gt('e.noActiveAfter', ':now'))
|
||||||
|
->orWhere($qb->expr()->isNull('e.noActiveAfter'));
|
||||||
|
$qb->setParameter('now', new \DateTime('now'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
And set your controller in configuration:
|
||||||
|
|
||||||
|
.. code-block:: yaml
|
||||||
|
|
||||||
|
chill_main:
|
||||||
|
apis:
|
||||||
|
accompanying_period_origin:
|
||||||
|
base_path: '/api/1.0/person/accompanying-period/origin'
|
||||||
|
class: 'Chill\PersonBundle\Entity\AccompanyingPeriod\Origin'
|
||||||
|
name: accompanying_period_origin
|
||||||
|
# add a controller
|
||||||
|
controller: 'Chill\PersonBundle\Controller\OpeningApiController'
|
||||||
|
base_role: 'ROLE_USER'
|
||||||
|
actions:
|
||||||
|
_index:
|
||||||
|
methods:
|
||||||
|
GET: true
|
||||||
|
HEAD: true
|
||||||
|
_entity:
|
||||||
|
methods:
|
||||||
|
GET: true
|
||||||
|
HEAD: true
|
||||||
|
|
||||||
|
Create your own actions
|
||||||
|
=======================
|
||||||
|
|
||||||
|
You can add your own actions:
|
||||||
|
|
||||||
|
.. code-block:: yaml
|
||||||
|
|
||||||
|
chill_main:
|
||||||
|
apis:
|
||||||
|
-
|
||||||
|
class: Chill\PersonBundle\Entity\AccompanyingPeriod
|
||||||
|
name: accompanying_course
|
||||||
|
base_path: /api/1.0/person/accompanying-course
|
||||||
|
controller: Chill\PersonBundle\Controller\AccompanyingCourseApiController
|
||||||
|
actions:
|
||||||
|
# add a custom participation:
|
||||||
|
participation:
|
||||||
|
methods:
|
||||||
|
POST: true
|
||||||
|
DELETE: true
|
||||||
|
GET: false
|
||||||
|
HEAD: false
|
||||||
|
PUT: false
|
||||||
|
roles:
|
||||||
|
POST: CHILL_PERSON_ACCOMPANYING_PERIOD_SEE
|
||||||
|
DELETE: CHILL_PERSON_ACCOMPANYING_PERIOD_SEE
|
||||||
|
GET: null
|
||||||
|
HEAD: null
|
||||||
|
PUT: null
|
||||||
|
single-collection: single
|
||||||
|
|
||||||
|
The key :code:`single-collection` with value :code:`single` will add a :code:`/{id}/ + "action name"` (in this example, :code:`/{id}/participation`) into the path, after the base path. If the value is :code:`collection`, no id will be set, but the action name will be append to the path.
|
||||||
|
|
||||||
|
Then, create the corresponding action into your controller:
|
||||||
|
|
||||||
|
.. code-block:: php
|
||||||
|
|
||||||
|
namespace Chill\PersonBundle\Controller;
|
||||||
|
|
||||||
|
use Chill\MainBundle\CRUD\Controller\ApiController;
|
||||||
|
use Symfony\Component\HttpFoundation\Request;
|
||||||
|
use Symfony\Component\HttpFoundation\Response;
|
||||||
|
use Chill\PersonBundle\Entity\AccompanyingPeriod;
|
||||||
|
use Symfony\Component\HttpFoundation\Exception\BadRequestException;
|
||||||
|
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
|
||||||
|
use Symfony\Component\Validator\Validator\ValidatorInterface;
|
||||||
|
use Chill\PersonBundle\Privacy\AccompanyingPeriodPrivacyEvent;
|
||||||
|
use Chill\PersonBundle\Entity\Person;
|
||||||
|
|
||||||
|
class AccompanyingCourseApiController extends ApiController
|
||||||
|
{
|
||||||
|
protected EventDispatcherInterface $eventDispatcher;
|
||||||
|
|
||||||
|
protected ValidatorInterface $validator;
|
||||||
|
|
||||||
|
public function __construct(EventDispatcherInterface $eventDispatcher, $validator)
|
||||||
|
{
|
||||||
|
$this->eventDispatcher = $eventDispatcher;
|
||||||
|
$this->validator = $validator;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function participationApi($id, Request $request, $_format)
|
||||||
|
{
|
||||||
|
/** @var AccompanyingPeriod $accompanyingPeriod */
|
||||||
|
$accompanyingPeriod = $this->getEntity('participation', $id, $request);
|
||||||
|
$person = $this->getSerializer()
|
||||||
|
->deserialize($request->getContent(), Person::class, $_format, []);
|
||||||
|
|
||||||
|
if (NULL === $person) {
|
||||||
|
throw new BadRequestException('person id not found');
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->onPostCheckACL('participation', $request, $accompanyingPeriod, $_format);
|
||||||
|
|
||||||
|
switch ($request->getMethod()) {
|
||||||
|
case Request::METHOD_POST:
|
||||||
|
$participation = $accompanyingPeriod->addPerson($person);
|
||||||
|
break;
|
||||||
|
case Request::METHOD_DELETE:
|
||||||
|
$participation = $accompanyingPeriod->removePerson($person);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new BadRequestException("This method is not supported");
|
||||||
|
}
|
||||||
|
|
||||||
|
$errors = $this->validator->validate($accompanyingPeriod);
|
||||||
|
|
||||||
|
if ($errors->count() > 0) {
|
||||||
|
// only format accepted
|
||||||
|
return $this->json($errors);
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->getDoctrine()->getManager()->flush();
|
||||||
|
|
||||||
|
return $this->json($participation);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.. api_full_config:
|
||||||
|
|
||||||
|
Full configuration example
|
||||||
|
==========================
|
||||||
|
|
||||||
|
.. code-block:: yaml
|
||||||
|
|
||||||
|
apis:
|
||||||
|
-
|
||||||
|
class: Chill\PersonBundle\Entity\AccompanyingPeriod
|
||||||
|
name: accompanying_course
|
||||||
|
base_path: /api/1.0/person/accompanying-course
|
||||||
|
controller: Chill\PersonBundle\Controller\AccompanyingCourseApiController
|
||||||
|
actions:
|
||||||
|
_entity:
|
||||||
|
roles:
|
||||||
|
GET: CHILL_PERSON_ACCOMPANYING_PERIOD_SEE
|
||||||
|
HEAD: null
|
||||||
|
POST: null
|
||||||
|
DELETE: null
|
||||||
|
PUT: null
|
||||||
|
controller_action: null
|
||||||
|
path: null
|
||||||
|
single-collection: single
|
||||||
|
methods:
|
||||||
|
GET: true
|
||||||
|
HEAD: true
|
||||||
|
POST: false
|
||||||
|
DELETE: false
|
||||||
|
PUT: false
|
||||||
|
participation:
|
||||||
|
methods:
|
||||||
|
POST: true
|
||||||
|
DELETE: true
|
||||||
|
GET: false
|
||||||
|
HEAD: false
|
||||||
|
PUT: false
|
||||||
|
roles:
|
||||||
|
POST: CHILL_PERSON_ACCOMPANYING_PERIOD_SEE
|
||||||
|
DELETE: CHILL_PERSON_ACCOMPANYING_PERIOD_SEE
|
||||||
|
GET: null
|
||||||
|
HEAD: null
|
||||||
|
PUT: null
|
||||||
|
controller_action: null
|
||||||
|
# the requirements for the route. Will be set to `[ 'id' => '\d+' ]` if left empty.
|
||||||
|
requirements: []
|
||||||
|
path: null
|
||||||
|
single-collection: single
|
||||||
|
base_role: null
|
||||||
|
|
||||||
|
|
Loading…
x
Reference in New Issue
Block a user