Skip to content
Snippets Groups Projects
Unverified Commit d536d80e authored by Mateu Aguiló Bosch's avatar Mateu Aguiló Bosch Committed by Mateu Aguiló Bosch
Browse files

Issue #2997956 by e0ipso, rhristov, mkolar, Wim Leers, ndobromirov, yobottehg:...

Issue #2997956 by e0ipso, rhristov, mkolar, Wim Leers, ndobromirov, yobottehg: Join modules together (Extras & Defaults)
parent 0aa1381f
Branches
Tags
No related merge requests found
Showing
with 814 additions and 3 deletions
......@@ -7,6 +7,14 @@
{
"name": "Mateu Aguiló Bosch",
"email": "mateu.aguilo.bosch@gmail.com"
},
{
"name": "Martin Kolar",
"homepage": "https://www.drupal.org/u/mkolar"
},
{
"name": "Karel Majzlik",
"homepage": "https://www.drupal.org/u/karlos007"
}
],
"require": {
......
===================
JSON API Defaults
===================
The JSON API module provides zero configuration out of the box. Use JSON API Extras and Defaults to customize your API. JSON API Defaults provides default includes and filters (or any parameter) for resources. Use this module if you want your api client just use simple resource without any url parameters and still deliver all related objects.
Here are the current features of the JSON API Defaults module:
- Default includes: if you apply default includes to a resource type, then collections of that
resource type will apply those includes when there is no include in the collection query.
- Default filters: if you apply default filters to a resource type, then collections of that
resource type will apply those filters when there is no filter in the collection query.
--------------
Installation
--------------
- Install the JSON API Defaults module normally.
- Visit /admin/config/services/jsonapi to overwrite and configure your API.
jsonapi_extras.jsonapi_resource_config.*.third_party.jsonapi_defaults:
type: mapping
label: 'JSONAPI Defaults settings'
mapping:
default_include:
type: sequence
label: 'Default includes list'
sequence:
type: string
label: 'Key and value'
default_filter:
type: sequence
label: 'Default filters list'
sequence:
type: string
label: 'Key and value'
name: JSON API Defaults
type: module
description: Builds on top of JSON API to deliver extra functionality.
core: 8.x
package: Web services
dependencies:
- jsonapi (>= 8.x-2.0-beta1)
- jsonapi_extras
<?php
/**
* @file
* Install, update and uninstall functions for the JSON API Defaults module.
*/
/**
* Update third party settings default_include.
*/
function jsonapi_defaults_update_8001() {
/** @var \Drupal\Core\Config\ConfigFactoryInterface $config_factory */
$config_factory = \Drupal::configFactory();
/** @var \Drupal\Core\Config\Config $config */
$config_list = $config_factory->listAll('jsonapi_extras.jsonapi_resource_config');
foreach ($config_list as $config) {
$config = $config_factory->getEditable($config);
$third_party = $config->get('third_party_settings');
if (isset($third_party['jsonapi_defaults']['default_include'])
&& is_string($third_party['jsonapi_defaults']['default_include'])
) {
$third_party_defaults = str_replace(" ", "", $third_party['jsonapi_defaults']['default_include']);
$third_party_array = explode(",", $third_party_defaults);
$third_party['jsonapi_defaults']['default_include'] = $third_party_array;
$config->set('third_party_settings', $third_party);
$config->save();
}
}
}
<?php
/**
* @file
* Contains module related hooks.
*/
use Drupal\Core\Form\FormStateInterface;
use Drupal\jsonapi_extras\Entity\JsonapiResourceConfig;
/**
* Implements hook_form_FORM_ID_alter().
*/
function jsonapi_defaults_form_jsonapi_resource_config_add_form_alter(&$form, FormStateInterface $form_state, $form_id) {
_jsonapi_defaults_form_alter($form, $form_state);
}
/**
* Implements hook_form_FORM_ID_alter().
*/
function jsonapi_defaults_form_jsonapi_resource_config_edit_form_alter(&$form, FormStateInterface $form_state, $form_id) {
_jsonapi_defaults_form_alter($form, $form_state);
}
/**
* Build JSON API Defaults part of the form.
*
* @param array $form
* Drupal form array.
* @param \Drupal\Core\Form\FormStateInterface $form_state
* Drupal form_state object.
*/
function _jsonapi_defaults_form_alter(array &$form, FormStateInterface $form_state) {
/** @var \Drupal\jsonapi_extras\Entity\JsonapiResourceConfig $config_resource */
$config_resource = $form_state->getFormObject()->getEntity();
$filters = _jsonapi_defaults_convert_value(
$config_resource->getThirdPartySetting('jsonapi_defaults', 'default_filter')
);
$includes = $config_resource->getThirdPartySetting(
'jsonapi_defaults',
'default_include'
);
$form['bundle_wrapper']['fields_wrapper']['defaults'] = [
'#type' => 'details',
'#title' => t('Collection'),
'#open' => $includes || $filters,
'#description' => t('Sets resource default parameters.'),
'#states' => [
'visible' => [
':input[name="disabled"]' => ['checked' => FALSE],
],
],
];
$form['bundle_wrapper']['fields_wrapper']['defaults']['default_include'] = [
'#type' => 'textarea',
'#title' => 'Default include list',
'#default_value' => $includes ? implode("\n", $includes) : '',
'#description' => t('Specify includes here (For example uid or field_image). Enter one include per line. If a request contains an "include" query string parameter this defaults will be ignored.'),
];
$form['bundle_wrapper']['fields_wrapper']['defaults']['default_filter'] = [
'#type' => 'textarea',
'#title' => 'Default filter list',
'#default_value' => $filters,
'#description' => t('Enter one filter per line, in the format key=value. For example:<br />
filter[titleFilter][condition][path]=title<br />
filter[titleFilter][condition][value]=Comis Commodo Ymo<br />
If a request contains an "filter" query string parameter those filters will be added to the defaults.'),
];
$form['#entity_builders'][] = 'jsonapi_defaults_form_jsonapi_resource_config_form_builder';
}
/**
* Entity builder for json api resource configuration entity.
*/
function jsonapi_defaults_form_jsonapi_resource_config_form_builder($entity_type, JsonapiResourceConfig $config_resource, &$form, FormStateInterface $form_state) {
if ($raw_value = $form_state->getValue('default_filter')) {
$value = _jsonapi_defaults_convert_rawvalue($raw_value);
$config_resource->setThirdPartySetting('jsonapi_defaults', 'default_filter', $value);
}
else {
$config_resource->unsetThirdPartySetting('jsonapi_defaults', 'default_filter');
}
if ($raw_value = $form_state->getValue('default_include')) {
$include = array_map('trim', preg_split('/\r\n?|\n/', $raw_value));
$include = array_filter($include);
$config_resource->setThirdPartySetting('jsonapi_defaults', 'default_include', $include);
}
else {
$config_resource->unsetThirdPartySetting('jsonapi_defaults', 'default_include');
}
}
/**
* Convert default parameters value to array (used in config).
*
* @param string|null $raw_value
* Raw value from textarea.
*
* @return array
* Value to be saved into config.
*/
function _jsonapi_defaults_convert_rawvalue($raw_value) {
$value = [];
$raw_value = (!is_string($raw_value)) ? '' : $raw_value;
foreach (preg_split('/\r\n|[\r\n]/', $raw_value) as $param) {
if (strpos($param, '=') !== FALSE) {
$a = explode('=', $param);
$key = $a[0];
$val = $a[1];
if ($key == 'include') {
$value[$key] = trim($val);
}
elseif (preg_match('/^filter.+/', $key)) {
$key = str_replace('filter[', '', $key);
$key = explode('][', $key);
$value['filter:' . trim(implode('#', $key), '[]')] = $val;
}
}
}
return $value;
}
/**
* Convert default parameters value to raw value (textarea).
*
* @param array|null $value
* Value from config.
*
* @return string
* Value to be shown in textarea.
*/
function _jsonapi_defaults_convert_value($value) {
$raw_value = '';
if (is_array($value)) {
foreach ($value as $key => $val) {
if ($key == 'include') {
$raw_value .= "$key=$val\n";
}
elseif (preg_match('/^filter.+/', $key)) {
$key = implode('][', explode('#', preg_replace('/^filter:/', '', $key)));
$raw_value .= "filter[$key]=$val\n";
}
}
}
return $raw_value;
}
<?php
namespace Drupal\jsonapi_defaults\Controller;
use Drupal\Component\Serialization\Json;
use Drupal\jsonapi\Controller\EntityResource as JsonApiEntityResourse;
use Drupal\jsonapi\ResourceType\ResourceType;
use Drupal\jsonapi\Routing\Routes;
use Drupal\jsonapi_extras\Entity\JsonapiResourceConfig;
use Drupal\jsonapi_extras\ResourceType\ConfigurableResourceType;
use Symfony\Component\HttpFoundation\Request;
/**
* Overrides jsonapi module EntityResource controller.
*/
class EntityResource extends JsonApiEntityResourse {
/**
* {@inheritdoc}
*/
public function getIncludes(Request $request, $data, $related = NULL) {
/** @var \Drupal\jsonapi_extras\ResourceType\ConfigurableResourceType $resourceConfig */
if (
($resource_type = $request->get(Routes::RESOURCE_TYPE_KEY))
&& $resource_type instanceof ConfigurableResourceType
&& !$request->get('_on_relationship')
) {
try {
$resource_type = static::correctResourceTypeOnRelated($request->get('related'), $resource_type);
}
catch (\LengthException $e) {
watchdog_exception('jsonapi_defaults', $e);
return parent::getIncludes($request, $data, $related);
}
if (!$resource_type instanceof ConfigurableResourceType) {
return parent::getIncludes($request, $data, $related);
}
$resource_config = $resource_type->getJsonapiResourceConfig();
if (!$resource_config instanceof JsonapiResourceConfig) {
return parent::getIncludes($request, $data, $related);
}
$default_includes = $resource_config->getThirdPartySetting(
'jsonapi_defaults',
'default_include',
[]
);
if (!empty($default_includes) && $request->query->get('include') === NULL) {
$includes = array_unique(array_filter(array_merge(
$default_includes,
explode(',', $request->query->get('include', ''))
)));
$request->query->set('include', implode(',', $includes));
}
}
return parent::getIncludes($request, $data, $related);
}
/**
* Returns the correct resource type when operating on related fields.
*
* @param string $related_field
* The name of the related field to use. NULL if not using a related field.
* @param \Drupal\jsonapi\ResourceType\ResourceType $resource_type
* The resource type straight from the request.
*
* @return \Drupal\jsonapi\ResourceType\ResourceType
* The resource type to use to load the includes.
*
* @throws \LengthException
* If there is more than one relatable resource type.
*/
public static function correctResourceTypeOnRelated($related_field, ResourceType $resource_type) {
if (!$related_field) {
return $resource_type;
}
$relatable_resource_types = $resource_type
->getRelatableResourceTypesByField($related_field);
if (count($relatable_resource_types) > 1) {
$message = sprintf(
'%s -- %s',
'Impossible to apply defaults on a related resource with heterogeneous resource types.',
Json::encode([
'related_field' => $related_field,
'host_resource_type' => $resource_type->getPath(),
'target_resource_types' => array_map(function (ResourceType $resource_type) {
return $resource_type->getPath();
}, $relatable_resource_types),
])
);
throw new \LengthException($message);
}
return $relatable_resource_types[0];
}
}
<?php
namespace Drupal\jsonapi_defaults;
use Drupal\jsonapi\Routing\JsonApiParamEnhancer;
use Drupal\jsonapi\Routing\Routes;
use Drupal\jsonapi_defaults\Controller\EntityResource;
use Drupal\jsonapi_extras\Entity\JsonapiResourceConfig;
use Drupal\jsonapi_extras\ResourceType\ConfigurableResourceType;
use Symfony\Cmf\Component\Routing\RouteObjectInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\HttpFoundation\Request;
/**
* JsonApiDefaultsJsonApiParamEnhancer class.
*
* @internal
*/
class JsonApiDefaultsJsonApiParamEnhancer extends JsonApiParamEnhancer {
/**
* Configuration manager.
*
* @var \Drupal\Core\Config\ConfigManagerInterface
*/
protected $configManager;
/**
* {@inheritdoc}
*/
public function setContainer(ContainerInterface $container = NULL) {
parent::setContainer($container);
$this->configManager = $container->get('config.manager');
}
/**
* {@inheritdoc}
*/
public function enhance(array $defaults, Request $request) {
if (!Routes::isJsonApiRequest($defaults)) {
return parent::enhance($defaults, $request);
}
$resource_type = Routes::getResourceTypeNameFromParameters($defaults);
// If this is a related resource, then we need to swap to the new resource
// type.
$route = $defaults[RouteObjectInterface::ROUTE_OBJECT];
$related_field = $route->getDefault('_on_relationship')
? NULL
: $route->getDefault('related');
try {
$resource_type = EntityResource::correctResourceTypeOnRelated($related_field, $resource_type);
}
catch (\LengthException $e) {
watchdog_exception('jsonapi_defaults', $e);
$resource_type = NULL;
}
if (!$resource_type instanceof ConfigurableResourceType) {
return parent::enhance($defaults, $request);
}
$resource_config = $resource_type->getJsonapiResourceConfig();
if (!$resource_config instanceof JsonapiResourceConfig) {
return parent::enhance($defaults, $request);
}
$default_filter_input = $resource_config->getThirdPartySetting(
'jsonapi_defaults',
'default_filter',
[]
);
$default_filter = [];
foreach ($default_filter_input as $key => $value) {
if (substr($key, 0, 6) === 'filter') {
$key = str_replace('filter:', '', $key);
// TODO: Replace this with use of the NestedArray utility.
$this->setFilterValue($default_filter, $key, $value);
}
}
$filters = array_merge(
$default_filter,
$request->query->get('filter', [])
);
if (!empty($filters)) {
$request->query->set('filter', $filters);
}
return parent::enhance($defaults, $request);
}
/**
* Set filter into nested array.
*
* @param array $arr
* The default filter.
* @param string $path
* The filter path.
* @param mixed $value
* The filter value.
*/
private function setFilterValue(array &$arr, $path, $value) {
$keys = explode('#', $path);
foreach ($keys as $key) {
$arr = &$arr[$key];
}
$arr = $value;
}
}
<?php
namespace Drupal\jsonapi_defaults;
use Drupal\Core\DependencyInjection\ContainerBuilder;
use Drupal\Core\DependencyInjection\ServiceProviderBase;
/**
* Modifies the jsonapi normalizer service.
*/
class JsonapiDefaultsServiceProvider extends ServiceProviderBase {
/**
* {@inheritdoc}
*/
public function alter(ContainerBuilder $container) {
/** @var \Symfony\Component\DependencyInjection\Definition $definition */
if ($container->hasDefinition('jsonapi.params.enhancer')) {
$definition = $container->getDefinition('jsonapi.params.enhancer');
$definition->setClass('Drupal\jsonapi_defaults\JsonApiDefaultsJsonApiParamEnhancer');
}
if ($container->hasDefinition('jsonapi.entity_resource')) {
$definition = $container->getDefinition('jsonapi.entity_resource');
$definition->setClass('Drupal\jsonapi_defaults\Controller\EntityResource');
}
}
}
<?php
namespace Drupal\Tests\jsonapi_defaults\Functional;
use Drupal\Component\Serialization\Json;
use Drupal\jsonapi_extras\Entity\JsonapiResourceConfig;
use Drupal\Tests\jsonapi_extras\Functional\JsonApiExtrasFunctionalTestBase;
/**
* The test class for the JSON API Defaults functionality.
*
* @group jsonapi_extras
*/
class JsonApiDefaultsFunctionalTest extends JsonApiExtrasFunctionalTestBase {
public static $modules = [
'jsonapi_defaults',
];
/**
* Test the GET method.
*/
public function testRead() {
$this->createDefaultContent(4, 5, TRUE, TRUE, static::IS_NOT_MULTILINGUAL);
// 1. Apply default filters and includes on a resource and a related
// resource.
$response = $this->drupalGet('/api/articles');
$parsed_response = Json::decode($response);
$this->assertArrayHasKey('data', $parsed_response);
$this->assertCount(1, $parsed_response['data']);
$this->assertEquals(3, $parsed_response['data'][0]['attributes']['internalId']);
$this->assertArrayHasKey('included', $parsed_response);
$this->assertGreaterThan(0, count($parsed_response['included']));
// Make sure related resources don't fail.
$response = $this->drupalGet('/api/articles/' . $this->nodes[0]->uuid() . '/owner');
$parsed_response = Json::decode($response);
$this->assertArrayHasKey('data', $parsed_response);
$this->assertEquals('user--user', $parsed_response['data']['type']);
// 2. Merge default filters with explicit filters.
$response = $this->drupalGet('/api/articles', [
'query' => [
'filter' => [
'i' => [
'condition' => [
'path' => 'internalId',
'value' => '2',
],
],
],
],
]);
$parsed_response = Json::decode($response);
$this->assertArrayHasKey('data', $parsed_response);
// internalId cannot be 2 and 3 at the same time.
$this->assertCount(0, $parsed_response['data']);
// 3. Override the default includes.
$response = $this->drupalGet('/api/articles', [
'query' => ['include' => ''],
]);
$parsed_response = Json::decode($response);
$this->assertArrayNotHasKey('included', $parsed_response);
}
/**
* Creates the JSON API Resource Config entities to override the resources.
*/
protected static function overrideResources() {
// Override paths and fields in the articles resource.
JsonapiResourceConfig::create([
'id' => 'node--article',
'third_party_settings' => [
'jsonapi_defaults' => [
'default_filter' => [
'filter:nidFilter#condition#path' => 'internalId',
'filter:nidFilter#condition#value' => 3,
],
// TODO: Change this to 'tags.vid'.
'default_include' => ['tags'],
],
],
'disabled' => FALSE,
'path' => 'articles',
'resourceType' => 'articles',
'resourceFields' => [
'nid' => [
'fieldName' => 'nid',
'publicName' => 'internalId',
'enhancer' => ['id' => ''],
'disabled' => FALSE,
],
'uuid' => [
'fieldName' => 'uuid',
'publicName' => 'uuid',
'enhancer' => ['id' => ''],
'disabled' => TRUE,
],
'vid' => [
'fieldName' => 'vid',
'publicName' => 'vid',
'enhancer' => ['id' => ''],
'disabled' => TRUE,
],
'langcode' => [
'fieldName' => 'langcode',
'publicName' => 'langcode',
'enhancer' => ['id' => ''],
'disabled' => TRUE,
],
'type' => [
'fieldName' => 'type',
'publicName' => 'contentType',
'enhancer' => ['id' => ''],
'disabled' => FALSE,
],
'status' => [
'fieldName' => 'status',
'publicName' => 'isPublished',
'enhancer' => ['id' => ''],
'disabled' => FALSE,
],
'title' => [
'fieldName' => 'title',
'publicName' => 'title',
'enhancer' => ['id' => ''],
'disabled' => FALSE,
],
'uid' => [
'fieldName' => 'uid',
'publicName' => 'owner',
'enhancer' => ['id' => ''],
'disabled' => FALSE,
],
'created' => [
'fieldName' => 'created',
'publicName' => 'createdAt',
'enhancer' => [
'id' => 'date_time',
'settings' => ['dateTimeFormat' => 'Y-m-d\TH:i:sO'],
],
'disabled' => FALSE,
],
'changed' => [
'fieldName' => 'changed',
'publicName' => 'updatedAt',
'enhancer' => [
'id' => 'date_time',
'settings' => ['dateTimeFormat' => 'Y-m-d\TH:i:sO'],
],
'disabled' => FALSE,
],
'promote' => [
'fieldName' => 'promote',
'publicName' => 'isPromoted',
'enhancer' => ['id' => ''],
'disabled' => FALSE,
],
'sticky' => [
'fieldName' => 'sticky',
'publicName' => 'sticky',
'enhancer' => ['id' => ''],
'disabled' => TRUE,
],
'revision_timestamp' => [
'fieldName' => 'revision_timestamp',
'publicName' => 'revision_timestamp',
'enhancer' => ['id' => ''],
'disabled' => TRUE,
],
'revision_uid' => [
'fieldName' => 'revision_uid',
'publicName' => 'revision_uid',
'enhancer' => ['id' => ''],
'disabled' => TRUE,
],
'revision_log' => [
'fieldName' => 'revision_log',
'publicName' => 'revision_log',
'enhancer' => ['id' => ''],
'disabled' => TRUE,
],
'revision_translation_affected' => [
'fieldName' => 'revision_translation_affected',
'publicName' => 'revision_translation_affected',
'enhancer' => ['id' => ''],
'disabled' => TRUE,
],
'default_langcode' => [
'fieldName' => 'default_langcode',
'publicName' => 'default_langcode',
'enhancer' => ['id' => ''],
'disabled' => TRUE,
],
'path' => [
'fieldName' => 'path',
'publicName' => 'path',
'enhancer' => ['id' => ''],
'disabled' => FALSE,
],
'body' => [
'fieldName' => 'body',
'publicName' => 'body',
'enhancer' => ['id' => 'nested', 'settings' => ['path' => 'value']],
'disabled' => FALSE,
],
'field_link' => [
'fieldName' => 'field_link',
'publicName' => 'link',
'enhancer' => ['id' => 'uuid_link'],
'disabled' => FALSE,
],
'field_timestamp' => [
'fieldName' => 'field_timestamp',
'publicName' => 'timestamp',
'enhancer' => [
'id' => 'date_time',
'settings' => ['dateTimeFormat' => 'Y-m-d\TH:i:sO'],
],
'disabled' => FALSE,
],
'comment' => [
'fieldName' => 'comment',
'publicName' => 'comment',
'enhancer' => ['id' => ''],
'disabled' => FALSE,
],
'field_image' => [
'fieldName' => 'field_image',
'publicName' => 'image',
'enhancer' => ['id' => ''],
'disabled' => FALSE,
],
'field_recipes' => [
'fieldName' => 'field_recipes',
'publicName' => 'recipes',
'enhancer' => ['id' => ''],
'disabled' => FALSE,
],
'field_tags' => [
'fieldName' => 'field_tags',
'publicName' => 'tags',
'enhancer' => ['id' => ''],
'disabled' => FALSE,
],
],
])->save();
}
}
......@@ -243,10 +243,11 @@ class JsonapiResourceConfigForm extends EntityForm {
$field_names = $this->getAllFieldNames($entity_type, $bundle);
$overrides_form['overrides']['entity'] = [
'#type' => 'details',
'#title' => $this->t('Entity'),
'#type' => 'fieldset',
'#title' => $this->t('Resource'),
'#description' => $this->t('Override configuration for the resource entity.'),
'#open' => !$entity->get('resourceType') || !$entity->get('path'),
'#weight' => 0,
];
$overrides_form['overrides']['entity']['disabled'] = [
......@@ -298,6 +299,7 @@ class JsonapiResourceConfigForm extends EntityForm {
'#type' => 'details',
'#title' => $this->t('Fields'),
'#open' => TRUE,
'#weight' => 1,
];
$markup = '';
......
......@@ -4,6 +4,7 @@
<testsuites>
<testsuite name="jsonapi_extras">
<directory>./src/</directory>
<directory>../modules/jsonapi_defaults/tests/src/</directory>
</testsuite>
</testsuites>
<!-- Filter for coverage reports. -->
......
......@@ -20,7 +20,7 @@ use Symfony\Component\Routing\Route;
*
* @group jsonapi_extras
*/
class JsonExtrasApiFunctionalTest extends JsonApiFunctionalTestBase {
class JsonApiExtrasFunctionalTest extends JsonApiFunctionalTestBase {
public static $modules = [
'jsonapi_extras',
......
<?php
namespace Drupal\Tests\jsonapi_extras\Functional;
use Drupal\Core\Field\FieldStorageDefinitionInterface;
use Drupal\field\Entity\FieldConfig;
use Drupal\field\Entity\FieldStorageConfig;
use Drupal\Tests\jsonapi\Functional\JsonApiFunctionalTestBase;
use Drupal\user\Entity\Role;
/**
* Provides helper methods for the JSON API Extras module's functional tests.
*
* @internal
*/
abstract class JsonApiExtrasFunctionalTestBase extends JsonApiFunctionalTestBase {
/**
* {@inheritdoc}
*/
protected function setUp() {
parent::setUp();
// Add vocabs field to the tags.
$this->createEntityReferenceField(
'taxonomy_term',
'tags',
'vocabs',
'Vocabularies',
'taxonomy_vocabulary',
'default',
[
'target_bundles' => [
'tags' => 'taxonomy_vocabulary',
],
'auto_create' => TRUE,
],
FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED
);
FieldStorageConfig::create([
'field_name' => 'field_timestamp',
'entity_type' => 'node',
'type' => 'timestamp',
'settings' => [],
'cardinality' => 1,
])->save();
$field_config = FieldConfig::create([
'field_name' => 'field_timestamp',
'label' => 'Timestamp',
'entity_type' => 'node',
'bundle' => 'article',
'required' => FALSE,
'settings' => [],
'description' => '',
]);
$field_config->save();
$config = \Drupal::configFactory()->getEditable('jsonapi_extras.settings');
$config->set('path_prefix', 'api');
$config->set('include_count', TRUE);
$config->save(TRUE);
$this->grantPermissions(Role::load(Role::ANONYMOUS_ID), ['access jsonapi resource list']);
static::overrideResources();
$this->resetAll();
$role = $this->user->get('roles')[0]->entity;
$this->grantPermissions($role, ['administer nodes', 'administer site configuration']);
}
/**
* {@inheritdoc}
*
* Appends the 'application/vnd.api+json' if there's no Accept header.
*/
protected function drupalGet($path, array $options = [], array $headers = []) {
if (empty($headers['Accept']) && empty($headers['accept'])) {
$headers['Accept'] = 'application/vnd.api+json';
}
return parent::drupalGet($path, $options, $headers);
}
/**
* Creates the JSON API Resource Config entities to override the resources.
*/
protected static function overrideResources() {}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment