I tried to create a custom Rest API with Drupal 8 and it was working great with GET operations. Problem is I wanted more, what about POST, PATCH, PUT, DELETE, … operations ?
Only GET examples were found about Drupal Rest API and nobody had any explanation about this POST response error:
Could not denormalize object of type , no supporting normalizer found.
So I had a look in Drupal Core and found out you need this interesting serialization_class comment annotation. Example with EntityResource:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
<?php namespace Drupal\rest\Plugin\rest\resource; use ... /** * Represents entities as resources. * * @RestResource( * id = "entity", * label = @Translation("Entity"), * serialization_class = "Drupal\Core\Entity\Entity", * deriver = "Drupal\rest\Plugin\Deriver\EntityDeriver", * uri_paths = { * "canonical" = "/entity/{entity_type}/{entity}", * "https://www.drupal.org/link-relations/create" = "/entity/{entity_type}" * } * ) * * @see \Drupal\rest\Plugin\Deriver\EntityDeriver */ class EntityResource extends ResourceBase { ... } |
Actually, if you implement GET, you don’t need this serialization_class to be filled because you only deal with primitive types, but if you want to implement something else like POST, PUT, …, this should be filled with an EntityType so Drupal would be able to understand and cast your parameters to the destination Entity.
Example, you create a VoteEntity and you need to implement GET and POST Rest apis, this should do the trick:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 |
<?php namespace Drupal\my_module\Plugin\rest\resource; use ... /** * Provides a resource to get view modes by entity and bundle. * * @RestResource( * id = "vote_resource", * label = @Translation("Vote resource"), * uri_paths = { * "canonical" = "/node/{node}/vote" * }, * serialization_class = "Drupal\my_module\Entity\VoteEntity" * ) */ class VoteResource extends ResourceBase { /** * Responds to GET requests. * * Returns a vote entry for the specified entity ID. * * @param int $entity_id * @return ResourceResponse * @throws \Symfony\Component\HttpKernel\Exception\HttpException */ public function get($entity_id) { if (!$this->currentUser->hasPermission('access content')) { throw new AccessDeniedHttpException(); } // $entity_id is the first parameter you specified between '{' and '}' /** @var VoteEntityInterface $vote */ $vote = \Drupal::entityTypeManager()->getStorage('vote')->loadByProperties(['user_id' => $this->currentUser->id(), 'entity_id' => $entity_id]); return new ResourceResponse($vote); } /** * Responds to POST requests. * * Create a vote entry for the specified entity ID. * * @param int $entity_id * @param VoteEntityInterface $newVote * @return ResourceResponse * @throws \Symfony\Component\HttpKernel\Exception\HttpException */ public function post($entity_id, VoteEntityInterface $newVote) { // The last parameter $newVote is the body of your request that Drupal will try to serialize into a VoteEntity object. // That's why you need to set a serializer_class because Drupal can't create this object with the default one. $newVote->setOwnerId($this->currentUser->id()); $newVote->setLinkedEntityId($entity_id); \Drupal::entityTypeManager()->getStorage('vote')->save($newVote); return new ResourceResponse("OK"); } } |
Hope this helps.
Hello,
thank you for that post.
I am wondering if there’s a way to use that post() function to add data in a custom table which is not following the Drupal 8 Entity schema.
In other words can I create a serialization_class which is not extending a Drupal 8 class?
If yes, what would that serialization_class looks like?