Drupal REST API

Piotr Woszczyk @ 2018

Paradyż

Do przygotowania API w projekcie Paradyż użyto nastepujacych komponentów:

  • Routing
  • Controller
  • Service

Routing

makolab.awards:
  path: '/json/api/awards'
  defaults:
    _controller: '\Drupal\makolab\Controller\AwardController::awardsList'
    _title: 'Awards listing'
  requirements:
    _permission: 'access content'

Controller

class AwardController extends JsonController
{
    protected $awardsService;

    public function __construct(
        AwardsService $awardsService
    ) {
        $this->awardsService = $awardsService;
    }
    
    public static function create(ContainerInterface $container)
    {
        return new static(
            $container->get('makolab.service.awards')
        );
    }
    
    public function awardsList()
    {
        $queryParams = \Drupal::request()->query->all();
        $results = json_encode($this->awardsService->get($queryParams));
        
        return $this->jsonResponse($results);
    }
}

Service

class AwardsService
{
    public function get($params)
    {
        $languageCode = \Drupal::languageManager()->getCurrentLanguage()->getId();

        $result = ['results' => [], 'total' => 0];

        $query = \Drupal::database()->select('node');
        $query->condition('type', 'award');

        // Tab filter
        $map = [
            '1' => 'dla_produktu',
            '2' => 'dla_firmy'
        ];
        $tab = isset($params['TAB']) ? $params['TAB'] : 1;
        $query->leftJoin('node__field_award_type', 'field_award_type', 'field_award_type.entity_id = node.nid');
        $query->condition('field_award_type.field_award_type_value', $map[$tab]);
        $query->condition('field_award_type.langcode', $languageCode);

        if (isset($params['featured'])) {
            $query->leftJoin('node__field_award_distinction', 'field_award_distinction', 'field_award_distinction.entity_id = node.nid');
            $query->condition('field_award_distinction.field_award_distinction_value', $params['featured']);
            $query->condition('field_award_distinction.langcode', $languageCode);
        }

        //...

        $elements = $countQuery->execute()->fetchAllKeyed(0, 0);
        $result['total'] = reset($elements);

        return $result;
    }
}

ECC

  • Rest resource + config

Rest resource

/**
 * @RestResource(
 *   id = "ecc:locations",
 *   label = @Translation("ECC Get Locations"),
 *   description = @Translation(
 *      "Used by search engine part, on the step 2 - download popup"
 *   ),
 *   uri_paths = {
 *     "canonical" = "/locations"
 *   }
 * )
 */

class RestResourceLocations extends ResourceBase {

//...

}

Config

#web/sites/default/config/rest.resource.search_products_results.yml

uuid: 6587b361-d46a-4f8b-b343-90820f60b466
langcode: fr
status: true
dependencies:
  module:
    - ecc_search
    - serialization
    - user
id: ecc.search_products_results
plugin_id: 'ecc:search_products_results'
granularity: resource
configuration:
  methods:
    - GET
  formats:
    - json
  authentication:
    - cookie

Paradyż

Zalety:

  • Prosta implementacja
  • Separacja logiki biznesowej w serwisach

Wady:

  • Nie ma to wiele wspólnego z REST
  • Problem z włączeniem cache / autoryzacji / formatów / CSRF protection

ECC

Zalety:

  • Użycie gotowego rozwiązania
  • Łatwość dodania cache, zmiany sposobu autoryzacji etc.

Wady:

  • Ogromne metody
  • Błędna implementacja response

ECC - response

  protected function getJson($output) {
    /**
     * @todo wylaczyc
     */
    return (new JsonResponse($output));

    if (! isset($output['#cache'])) {
      $output['#cache'] = [
        'max-age' => 1200, 
        'contexts' => [
          'url',
          'url.query_args'
        ],
      ];
    }

    $response = new CacheableJsonResponse($output);
    $response->addCacheableDependency(CacheableMetadata::createFromRenderArray($output));
    return $response;
  }

ResourceResponse

public function get() {
    $response = ['message' => 'Hello, this is a rest service'];
    return new ResourceResponse($response);
}

Drupal REST API (Paradyż vs ECC)

By Piotr Woszczyk

Drupal REST API (Paradyż vs ECC)

Prezentacja opisująca różnice w podejściu do implementacji API w projekcie Paradyż i ECC.

  • 62