REST Resource with GET & POST Method
In custom REST resource created in previous posts, Now in this post GET & POST both are implemented.
Create a file named NodeExamplesRestResource.php in firstcustommodule > src > Plugin > rest > resource.
Annotation for GET:-
<?php /** * @RestResource( * id = "custom_rest_endpoint_get", * label = @Translation("Endpoint GET"), * uri_paths = { * "canonical" = "/api/v1/article/{id}" * } * ) */
Annotation for POST:-
<?php
/**
* @RestResource(
* id = "custom_rest_endpoint_post",
* label = @Translation("Endpoint POST"),
* serialization_class = "",
* uri_paths = {
* "https://www.drupal.org/link-relations/create" = "/api/v1/email",
* }
* )
*/
Id and label is common in both, id is unique and it is machine name for our resource and label appears as a resource name in backend.
uri_path will define unique access / endpoint of our resource and so we do not need to define it routing.yml.
Now Code for file
<?php/**
* @file
* Contains \Drupal\firstcustommodule\Plugin\rest\resource\NodeExamplesRestResource
*
*/
namespace Drupal\firstcustommodule\Plugin\rest\resource;
use Drupal\Core\Session\AccountProxyInterface;
use Drupal\node\Entity\Node;
use Drupal\rest\ModifiedResourceResponse;
use Drupal\rest\Plugin\ResourceBase;
use Drupal\rest\ResourceResponse;
use Psr\Log\LoggerInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
/**
* Provides a resource to get view modes by entity and bundle.
*
* @RestResource(
* id = "node_example_rest_resource",
* label = @Translation("Node Example Create/Update/view Rest Resource"),
* serialization_class = "Drupal\node\Entity\Node",
* uri_paths = {
* "canonical" = "/examples-node-rest-resource",
* "https://www.drupal.org/link-relations/create" = "/examples-node-rest-resource"
* }
* )
*/
class NodeExamplesRestResource extends ResourceBase {
/**
* A current user instance.
*
* @var \Drupal\Core\Session\AccountProxyInterface
*/
protected $currentUser;
/**
* Constructs a new ExampleGetRestResource object.
*
* @param array $configuration
* A configuration array containing information about the plugin instance.
* @param string $plugin_id
* The plugin_id for the plugin instance.
* @param mixed $plugin_definition
* The plugin implementation definition.
* @param array $serializer_formats
* The available serialization formats.
* @param \Psr\Log\LoggerInterface $logger
* A logger instance.
* @param \Drupal\Core\Session\AccountProxyInterface $current_user
* A current user instance.
*/
public function __construct(
array $configuration,
$plugin_id,
$plugin_definition,
array $serializer_formats,
LoggerInterface $logger,
AccountProxyInterface $current_user) {
parent::__construct($configuration, $plugin_id, $plugin_definition, $serializer_formats, $logger);
$this->currentUser = $current_user;
}
/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
return new static(
$configuration, $plugin_id, $plugin_definition,
$container->getParameter('serializer.formats'),
$container->get('logger.factory')->get('example_node_rest'),
$container->get('current_user')
);
}
/**
* Responds to POST requests.
*
* @param \Drupal\Core\Entity\EntityInterface $entity
* The entity object.
*
* @return \Drupal\rest\ModifiedResourceResponse
* The HTTP response object.
*
* @throws \Symfony\Component\HttpKernel\Exception\HttpException
* Throws exception expected.
*/
public function post($node_data) {
// You must to implement the logic of your REST Resource here.
// Use current user after pass authentication to validate access.
if (!$this->currentUser->hasPermission('access content')) {
throw new AccessDeniedHttpException();
}
if ($node_data->nid->value == '') {
$node = Node::create([
'type' => $node_data->type->target_id,
'title' => $node_data->title->value,
'body' => [
'summary' => '',
'value' => $node_data->body->value,
'format' => 'full_html',
],
]);
$node->save();
}
elseif ($node_data->nid->value != '' && is_int($node_data->nid->value))
{
$values = \Drupal::entityQuery('node')->condition('nid', $node_data->nid->value)->execute();
$node_exists = !empty($values);
if ($node_exists) {
$node = Node::load($node_data->nid->value);
// Title field set
$node->setTitle($node_data->title->value);
// Body can now be an array with a value and a format.
// If body field exists.
$body = [
'value' => $node_data->body->value,
'format' => 'basic_html',
];
$node->set('body', $body);
$node->save();
//return new ResourceResponse($node);
}
else {
\Drupal::logger('example_node_rest_api')->error('Node nid '.$node_data->nid->value.' not exists' );
return new ResourceResponse(['Error'=>'Node nid not exists']);
}
}
else {
return new ResourceResponse(['Error'=>'Data not corrected']);
}
return new ResourceResponse($node);
}
/**
* Responds to GET requests.
*
* Returns a list of bundles for specified entity.
*
* @throws \Symfony\Component\HttpKernel\Exception\HttpException
* Throws exception expected.
*/
public function get() {
// You must to implement the logic of your REST Resource here.
// Use current user after pass authentication to validate access.
if (!$this->currentUser->hasPermission('access content')) {
throw new AccessDeniedHttpException();
}
$entities = \Drupal::entityTypeManager()
->getStorage('node')
->loadMultiple();
foreach ($entities as $entity) {
$result[$entity->id()] = $entity->title->value;
}
$response = new ResourceResponse($result);
// In order to generate fresh result every time (without clearing
// the cache), you need to invalidate the cache.
$response->addCacheableDependency($result);
return $response;
}
}
After saving above file, resource will start to appear in the resource list. Enable this resource with configuration as shown in screenshot.
Save this configuration.
Hit the url: localhost/examples-node-rest-resource/?_format=json
and response for the above url which is resource GET request response.
Now see the POST request. Open the above url in REST Client. I have used chrome REST client.
Resource Request URL: http://drupal8moduledevelopement.dd:8083/examples-node-rest-resource/?_format=json
Method: POST
Parameters:
Headers:
Content-Type: application/json
x-CSRF-Token: (copy the token from url: domainname/session/token OR domainname/rest/session/token)
authorization: Basic YWRtaW46YWRtaW4=
Body:
Body content type: Raw Input
Format Json:
{
"type": [
{
"target_id": "article"
}
],
"title": [
{
"value": "Article created by REST API 3rd"
}
],
"body": [
{
"value": "Rest api node create demo 3rd"
}
],
"nid": [
{
"value": ""
}
]
}
Output of above request:
{"nid":[{"value":4}],"uuid":[{"value":"45caea8e-4510-4107-92ce-83a5066f3203"}],"vid":[{"value":8}],"langcode":[{"value":"en"}],"type":[{"target_id":"article","target_type":"node_type","target_uuid":"c
fde2b7b-1839-4a83-a359-4b1416512055"}],"revision_timestamp":[{"value":"2019-03-17T12:57:26+00:00","format":"Y-m-d\\TH:i:sP"}],"revision_uid":[{"target_id":1,"target_type":"user","target_uuid":"52858798-09de-4fe5-81ae-048295f8f5cd","url":"\/user\/1"}],"revision_log":[],"status":[{"value":true}],"title":[{"value":"Article created by REST API "}],"uid":[{"target_id":1,"target_type":"user","target_uuid":"52858798-09de-4fe5-81ae-048295f8f5cd","url":"\/user\/1"}],"created":[{"value":"2019-03-17T12:57:26+00:00","format":"Y-m-d\\TH:i:sP"}],"changed":[{"value":"2019-03-17T12:57:26+00:00","format":"Y-m-d\\TH:i:sP"}],"promote":[{"value":true}],"sticky":[{"value":false}],"default_langcode":[{"value":true}],"revision_translation_affected":[{"value":true}],"path":[{"alias":null,"pid":null,"langcode":"en"}],"body":[{"value":"Rest api node create demo","format":"full_html","processed":"Rest api node create demo","summary":""}],"comment":[{"status":2,"cid":0,"last_comment_timestamp":0,"last_comment_name":null,"last_comment_uid":0,"comment_count":0}],"field_image":[],"field_tags":[]}
Hi it looks like your response object is not cached at all now.
ReplyDeleteThe addCacheableDependency method needs a object that implements CacheableDependencyInterface otherwise it will set the response as uncachable by setting max-age to 0.
If you apply the node_list cache tag it will cache the response object as long as no node is being updated.
To do so you can add:
$cache_metadata = new CacheableMetadata();
$cache_metadata->setCacheTags(['node_list']);
and then apply that object to your response object by:
$response->addCacheableDependency($cache_metadata);
Thanks for feedback.
Delete