web-dev-qa-db-ja.com

カスタムREST POST JSONを受け入れるリソース

シンプルな検索オートコンプリートを構築しようとしていますPOSTエンドポイント、JSONを受け入れ、JSONを出力しますが、Drupal 8を取得すると、プレーンなJSONを受け入れるだけで問題が発生します。

REST UIで有効になっていて、権限がある場合でも、そのエンドポイントで404エラーが発生します。serialization_classに値Drupal\node\Entity\Nodeを追加すると、クラスのコメント、ノードを想定しているため415エラーが発生します。わかりました。JSONを実際に受け入れるにはどうすればよいですか?オートコンプリート検索のためだけにエンティティタイプを作成する必要がありますか?

これがmymodule/src/Plugin/rest/resource/SearchAutocompleteResource.phpにあるコードです。

namespace Drupal\MyModule\Plugin\rest\resource;

use Drupal\rest\Plugin\ResourceBase;
use Drupal\rest\ResourceResponse;
use Drupal\node\Entity\Node;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;

/**
 * Provides a resource for search autocomplete.
 *
 * @RestResource(
 *   id = "mymodule:searchautocomplete",
 *   label = @Translation("MyModule: Search Autocomplete"),
 *   uri_paths = {
 *     "canonical" = "/api/v1/search-autocomplete",
 *     "https://www.drupal.org/link-relations/create" = "/api/v1/search-autocomplete"
 *   }
 * )
 */
class SearchAutocompleteResource extends ResourceBase {

  public function post($search = null) {

    return new ResourceResponse(array(
      'example' => 'return value'
    ));

  }

}
5
Risse

まで シリアル化クラスをオプションにする(#2419825)8.2.xブランチの問題が修正され、提供されたデータを渡すだけでカスタムのシリアル化クラスを作成せずに回避できなかったため、必須のシリアル化。

Drupal <= 8.1で動作させる必要がある場合は、以下を試してください:

  1. カスタムノーマライザーを作成します。
  2. サービスとしてシステムに公開します。
  3. Restリソースのserialization_classとして使用します。

modules/mymodule/src/normalizer/JsonDenormalizer.php:

<?php

namespace Drupal\mymodule\normalizer;

use Drupal\serialization\Normalizer\NormalizerBase;
use Symfony\Component\Serializer\Normalizer\DenormalizerInterface;

/**
 * Class JsonDenormalizer
 *
 * @todo Remove this class once https://www.drupal.org/node/2419825 is fixed.
 */
class JsonDenormalizer extends NormalizerBase implements DenormalizerInterface {

  /**
   * The interface or class that this Normalizer supports.
   *
   * @var array
   */
  protected $supportedInterfaceOrClass = array(__CLASS__);

  /**
   * {@inheritdoc}
   */
  public function normalize($object, $format = null, array $context = array()) {
    return parent::normalize($object, $format, $context);
  }

  /**
   * {@inheritdoc}
   */
  public function denormalize($data, $class, $format = NULL, array $context  = array()) {
    return $data;
  }
}

modules/mymodule/mymodule.services.yml:

services:
  # can be removed once https://www.drupal.org/node/2419825 is fixed.
  serializer.normalizer.mymodule.json:
    class: Drupal\mymodule\normalizer\JsonDenormalizer
    tags:
      - { name: normalizer }

mymodule/src/Plugin/rest/resource/SearchAutocompleteResource.php:

/**
 * Provides a resource for search autocomplete.
 *
 * @RestResource(
 *   id = "mymodule:searchautocomplete",
 *   label = @Translation("MyModule: Search Autocomplete"),
 *   serialization_class = "Drupal\mymodule\normalizer\JsonDenormalizer",
 *   uri_paths = {
 *     "canonical" = "/api/v1/search-autocomplete",
 *     "https://www.drupal.org/link-relations/create" = "/api/v1/search-autocomplete"
 *   }
 * )
 */
7
maijs

@maijsによって提供される答えはDrupal 8.1.x以下では正しいですが、8.2.xではsoです)ノーマライザについて考える必要がないため、はるかに簡単です。ここに_my_module/src/Plugin/rest/resource/MyRestResource.php_の例を示します。

_<?php

namespace Drupal\my_module\Plugin\rest\resource;

use Drupal\Core\Session\AccountProxyInterface;
use Drupal\rest\Plugin\ResourceBase;
use Drupal\rest\ResourceResponse;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
use Psr\Log\LoggerInterface;

/**
 * Provides a resource to get view modes by entity and bundle.
 *
 * @RestResource(
 *   id = "my_rest_resource",
 *   label = @Translation("My rest resource"),
 *   serialization_class = "",
 *   uri_paths = {
 *     "canonical" = "/my_rest_resource"
 *   }
 * )
 */
class MyRestResource extends ResourceBase {

  /**
   * A current user instance.
   *
   * @var \Drupal\Core\Session\AccountProxyInterface
   */
  protected $currentUser;

  /**
   * Constructs a Drupal\rest\Plugin\ResourceBase 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('my_module'),
      $container->get('current_user')
    );
  }

  /**
   * Responds to GET requests.
   *
   * Returns a list of bundles for specified entity.
   *
   * @throws \Symfony\Component\HttpKernel\Exception\HttpException
   *   Throws exception expected.
   */
  public function get() {
    $response = 'hello world';
    return new ResourceResponse($response);
  }

  public function post(array $data = []) {
    $response = array(
      "hello_world" => $data,
    );
    return new ResourceResponse($response);
  }

  public function patch($arg) {
    return new ResourceResponse('hello patch');
  }

}
_

ここでの鍵は、ファイルの下部にあるpost(array $data = [])です。 8.1.xでは不可能でしたが、8.2.xでは、投稿データを配列に変換するために必要なことはそれだけです。 postmanでそのURLをリクエストすると、次のようになります。

enter image description here

3
Matt Korostoff

これは、投稿からJSONオブジェクトを受け取るために行ったものです。

use Symfony\Component\HttpFoundation\Request;

class AjaxController extends ControllerBase {
    public function save(Request $request) {
        $object = json_decode($request->getContent());
1
Matt F