6

How I can add an optional parameter in drupal 8 REST API URL

"canonical" = "/content/get/{id}"

But I have to add value for id here, How I can make this id optional

2

I experienced the same issue and solved it by adding the current request from the request stack to my resource:

RestBase.php

<?php

namespace Drupal\api\Plugin\rest;

use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Psr\Log\LoggerInterface;
use Drupal\Core\Session\AccountProxyInterface;
use Drupal\rest\Plugin\ResourceBase;
use Drupal\rest\ResourceResponse;

class RestBase extends ResourceBase {

  /**
   *
   * @var \Drupal\Core\Session\AccountProxyInterface
   */
  protected $currentUser;
  /**
   *
   * @var \Symfony\Component\HttpFoundation\Request
   */
  protected $currentRequest;

  /**
   * 
   * @param array $configuration
   * @param type $pluginId
   * @param type $pluginDefinition
   * @param array $serializerFormats
   * @param \Drupal\api\Plugin\rest\resource\LoggerInterface $logger
   * @param \Drupal\api\Plugin\rest\resource\AccountProxyInterface $currentUser
   */
  public function __construct(array $configuration, $pluginId, $pluginDefinition, array $serializerFormats, LoggerInterface $logger, AccountProxyInterface $currentUser, Request $currentRequest) {
    parent::__construct($configuration, $pluginId, $pluginDefinition, $serializerFormats, $logger);

    $this->currentUser = $currentUser;
    $this->currentRequest = $currentRequest;
  }

  /**
   * {@inheritdoc}
   */
  public static function create(ContainerInterface $container, array $configuration, $pluginId, $pluginDefinition) {
    return new static(
        $configuration, 
        $pluginId, 
        $pluginDefinition, 
        $container->getParameter('serializer.formats'), 
        $container->get('logger.factory')->get('rest'), 
        $container->get('current_user'),
        $container->get('request_stack')->getCurrentRequest()
    );
  }

  /**
   * 
   * @param array $message
   * @param integer $cache
   * @return ResourceResponse
   */
  protected function getResponse($message, $cache = 0) {
    $build = [
      '#cache' => [
        'max-age' => $cache,
      ]
    ];

    $response = new ResourceResponse($message);
    $response->addCacheableDependency($build);

    return $response;
  }

}

TestResource.php (the actual REST resouce)

<?php

namespace Drupal\api\Plugin\rest\resource;

use Drupal\rest\ResourceResponse;
use Drupal\api\Plugin\rest\RestBase;

/**
 * Test resource.
 * 
 * @RestResource(
 *   id = "test_resource",
 *   label = @Translation("Test API Resource"),
 *   uri_paths = {
 *     "canonical" = "/api/test-resource"
 *   }
 * )
 */
class TestResource extends RestBase {

  /**
   * 
   * @return ResourceResponse
   */
  public function get() {
    if (!$this->currentUser->hasPermission('use ' . $this->pluginId . ' service')) {
      throw new AccessDeniedHttpException('Access denied.');
    }

    $id = $this->currentRequest->get('id');

    $message = [
      'message' => 'Hello, you called service: ' . $this->pluginId,
      'id' => $id,
    ];

    return parent::getResponse($message);
  }

}

In my own base class RestBase I added the current request from the request stack (besides the AccountProxy for permission purposes) by overriding the create method of the ResourceBase class. You can then access query parameters in your REST resource by calling the get($key) method on the request object.

You will need to pass your parameters in the API URI like so: http://localhost/api/test-resource?_format=<your-format>&<parameter1>=<value1>. Considering this example API URI you would access parameter1 via $value1 = $this->currentRequest->get('parameter1').

I guess that it is not possible to have slugs in your resources at the moment. If someone knows how please do tell :).

  • This works great. RestBase is optional though. You can just add the $currentRequest bits to your class MyResource extends ResourceBase. – Chance G Apr 6 '17 at 21:18
1

In your your_module.routing.yml file in your route configuration

defaults:
  id: 'default-id'

see here under Optional parameters for more information

If you are trying to alter existing route you should use RouteSubscriber

Or if you need to display something else on /content/get/ you should create additional route without {id}

  • Thanks for the answer, but I am using it as a REST plugin. I define the path using "@RestResource" annotation. I will try RouteSubscriber – Unnikrishnan Aug 31 '16 at 5:32
  • hi @Unnikrishnan are you found solution? – vijay Mar 2 '17 at 11:59
  • @vijay - not yet. – Unnikrishnan Mar 2 '17 at 12:13
0

There are some solutions on this page that explain how to do it. A different question is whether you should do it :)

From Drupal.org issue RestResource plugins: use get() method with optional parameter (or no parameter) to signal list support?:

One concept about the differences of collections and items:

A "collection resource" is likely to support POST and GET. An "individual item resource" will probably support GET, PUT, PATCH, and DELETE.

Another thought on general domain:

At least I think optional parameters are a flaw. I think on the REST domain level there is no notion of optional parameters. There is a collection resource and there is an individual object resource.

And about using Views:

The REST module basically has spent no time/thought on how to deal with collections. AFAICT it deferred that entirely to Views.

In summary: it seems the standard idea is that you can use Views for collections or you can write 2 Resources - one for the collection and one for the item.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.