Drupal - How to receive JSON data in controller with Drupal 8?
In case you want to do it more the D8 way here is a rough outline what you could do, which allows you to be flexible without the requirement to do everything in your own. A proper rest integration requires you to work with all the different HTTP status codes, header fields etc. Rest takes partly care of that
The rest module provides a generic abstraction for REST, not tight to entities in the first place. Entities are just one example.
First you should register your rest plugin, like every other plugin:
namespace Drupal\pinguin\Plugin\rest\resource;
use Drupal\rest\Plugin\ResourceBase;
/**
* Provides a resource for database watchdog log entries.
*
* @RestResource(
* id = "pinguin",
* label = @Translation("Example rest plugin for pinguins"),
* uri_paths = {
* "canonical" = "/pinguin/{id}"
* },
* serialization_class = "Drupal\pinguin\PingInterface"
* )
*/
class Pinguin extends ResourceBase {
}
If you do an updating request like PUSH or UPDATE, it uses the serializer component to convert your data into some php array/ object. It uses two steps in order to do that. First the data incoming is decoded, for example from JSON into a PHP array. The next step is the denormalization. This step converts the denormalized data (PHP array) into a domain object, for example the Ping (a single pinguin).
The first step is to specify the resulting class in the annotation (see above). To register a new denormalization you add the following entry into your .services.yml:
services:
pinguin.denormalizer.pinguin:
class: Drupal\pinguin\normalizer\PinguinDenormalizer
tags:
- { name: normalizer }
This normalizer specifies which interface it can convert to:
<?php
namespace Drupal\pinguin\normalizer;
use \Drupal\serialization\Normalizer\NormalizerBase;
class PinguinDenormalizer extends NormalizerBase {
// IMPORTANT
/**
* The interface or class that this Normalizer supports.
*
* @var array
*/
protected $supportedInterfaceOrClass = array('Drupal\pinguin\PingInterface');
/**
* {@inheritdoc}
*/
public function denormalize($data, $class, $format = NULL, array $context = array()) {
// Validate the data.
if (empty($data['location']) || $data['location'] == 'northpole') {
throw new \UnexpectedValueException("this can't be real pinguins");
}
// create the domain object.
return new Ping($data['name'], $data['location'], $data['family']);
}
}
Once this serialization is done, it calls a method named after the HTTP method on the plugin class, so for example "post". There you can do whatever you want.
<?php
class Pinguin extends ResourceBase {
public function post(PingInterface $ping) {
// deal with the data, save it for example.
$ping_storage->save($ping):
}
}
The advantages of these abstractions are that you don't have to deal with the incoming format but on the other hand it needs a bunch of code to get started.
Simply put: do not do this! Do not create your own table; that's not the way in Drupal 8. Much rather, have your own entity type. See https://drupal.stackexchange.com/a/95208/49 https://www.drupal.org/developing/api/entity https://api.drupal.org/api/drupal/core%21modules%21system%21core.api.php/group/entity_api/8 for more. The storage controller will generate the SQL schema for you and do all the storage work. The REST module will handle what you need. And so on.
Edit: For a generic case to receive and reply with JSON. First make sure there's not a Drupal API for it. Likely there is. REST gives you entities, Views gives you lists of entities (and lists of more).
If not then, you need to write a custom controller with the request as an argument. (see Parameters in routes for more) by just adding Request $request
as an argument.
To respond with JSON, any Response
object, among them JsonResponse
. Check TimezoneController::getTimeZone and the relevant routing entry in core/modules/system/system.routing.yml
.
So:
class MyController {
public function myJson(Request $request) {
$params = array();
$content = $request->getContent();
if (!empty($content)) {
// 2nd param to get as array
$params = json_decode($content, TRUE);
}
// Process $params...
return new JsonResponse($params);
}
}
In the controller's function how can I get the data posted with ajax and how to convert it to associative array?
use Drupal\Component\Serialization\Json;
//...
class MyController {
public function myPostAction(Request $request) {
$params = Json::decode($request->getContent());
//...
}
}