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