Commit 9b688a72 authored by aaa's avatar aaa

180306c - ok GET, POST, payload FWD working

parent 88882dc2
#guzzle rest endpoint
# guzzle rest endpoint
## Description:
This module repeats/relays an external API through the internal Drupal REST authentication/authorisation mechanism.
This is an extension to guzzlerestgenerator . It adds REST support to each guzzle_node. This exposes any external api defined in guzzle_node as a drupal8 REST point. Also, node_view_permissions module is also recommended.
Note : for relay_headers to work you need the modified guzzlerestgenerator module.
## Installation NOTE:
At this point you must manually enable guzzlenode_user_api_access and guzzlenode_role_api_access FIELDS from
http://mydrupalsite/admin/structure/types/manage/guzzle_rest/form-display
###Access rights:
This is a general permission to be able to access ALL guzzlenodes/external APIs (but not use them - you will need to specify usernames/roles inside EACH guzzlenode). Note 1: this ENABLES/DISABLES everything for everyone.So, you MUST have this permission in order to do anything. Note 2: From "RESTful Web Services" you can further control access to Drupal GET,POST,PATCH REST points. The final check is done when you check if the current USERNAME is declared in the specific guzzlenode
- Give permissions /admin/people/permissions to Drupal REST -> from here allow GET,POST,PATCH REST access to this drupal guzzlenode
- Give permissions /admin/people/permissions to All GuzzleNodes (initial access) -> **d8_guzzlenode_rest->GuzzleREST - General access to external guzzleAPIs** : This gives general access to external guzzleAPIs .(machine name: guzzlenode allow access to ext API guzzlenodes)
- by default all REST GET,POST are already activated from here : /admin/config/services/rest/resource/guzzlenode_rest_resource/edit
-
Notes:
ERRORS:
Error 4732 = This means that current username is NOT defined inside guzzlenode so we can allow him to access this resource.
Error 4532 = Resource disabled. This resource is unpublished (the specific guzzlenode is saved as unpublished).
## Usage administration-side:
First you enable from REST-UI guzzle node
......@@ -14,23 +33,28 @@ There you define:
- headers (eg APIkey etc.)
- Body (in case of POST/PUT)
Then you need to define access.
## Usage external-client-side:
## Usage external-client-side #1:
You can connect with urls like :
http://mydrupal.com/api/relay/getalbums?_format=hal_json&param1=Ubuntu&param2=Music
**http://mydrupal.com/api/relay/getalbums?_format=hal_json&param1=Ubuntu&param2=Music**
this will relay your request as
this will relay/forward your request as :
http://myjsonserver/albums/Ubuntu/Music
**http://myjsonserver/albums/Ubuntu/Music**
## Usage external-client-side #2:
###Parameters :
-
-
-
To Do:
##To Do:
- replace use Drupal\guzzlerestgenerator\Http\GuzzleDrupalHttp with a local one
- Implement POST
- Implement PUT
- Implement access per SPECIFIC guzzle_node (per role or user)
......
# core.entity_form_display.node.guzzle_rest.default.yml
langcode: en
status: true
dependencies:
config:
- field.field.node.guzzle_rest.body
- field.field.node.guzzle_rest.field_guzzle_data_payload
- field.field.node.guzzle_rest.field_guzzle_endpoint_url
- field.field.node.guzzle_rest.field_guzzle_raw_headers
- field.field.node.guzzle_rest.field_guzzle_request_method
- field.field.node.guzzle_rest.field_guzzlenode_role_api_access
- field.field.node.guzzle_rest.field_guzzlenode_user_api_access
- node.type.guzzle_rest
module:
- link
id: node.guzzle_rest.default
targetEntityType: node
bundle: guzzle_rest
mode: default
content:
field_guzzle_data_payload:
label: hidden
type: string_textarea
weight: 4
settings:
rows: 5
placeholder: ''
third_party_settings: { }
region: content
field_guzzle_endpoint_url:
type: link_default
weight: 1
region: content
settings:
placeholder_url: ''
placeholder_title: ''
third_party_settings: { }
field_guzzle_raw_headers:
type: string_textarea
weight: 3
region: content
settings:
rows: 5
placeholder: ''
third_party_settings: { }
field_guzzle_request_method:
type: options_select
weight: 2
region: content
settings: { }
third_party_settings: { }
field_guzzlenode_role_api_access:
weight: 102
settings:
match_operator: CONTAINS
size: 60
placeholder: ''
third_party_settings: { }
type: entity_reference_autocomplete
region: content
field_guzzlenode_user_api_access:
weight: 101
settings:
match_operator: CONTAINS
size: 60
placeholder: ''
third_party_settings: { }
type: entity_reference_autocomplete
region: content
links:
weight: 100
region: content
title:
type: string_textfield
weight: 0
region: content
settings:
size: 60
placeholder: ''
third_party_settings: { }
hidden:
body: true
created: true
path: true
promote: true
sticky: true
uid: true
# core.entity_view_display.node.guzzle_rest.default.yml
langcode: en
status: true
dependencies:
config:
- field.field.node.guzzle_rest.body
- field.field.node.guzzle_rest.field_guzzle_data_payload
- field.field.node.guzzle_rest.field_guzzle_endpoint_url
- field.field.node.guzzle_rest.field_guzzle_raw_headers
- field.field.node.guzzle_rest.field_guzzle_request_method
- field.field.node.guzzle_rest.field_guzzlenode_role_api_access
- field.field.node.guzzle_rest.field_guzzlenode_user_api_access
- node.type.guzzle_rest
module:
- text
- user
id: node.guzzle_rest.default
targetEntityType: node
bundle: guzzle_rest
mode: default
content:
body:
label: hidden
type: text_default
weight: 101
settings: { }
third_party_settings: { }
region: content
field_guzzlenode_role_api_access:
weight: 103
label: above
settings:
link: true
third_party_settings: { }
type: entity_reference_label
region: content
field_guzzlenode_user_api_access:
weight: 102
label: above
settings:
link: true
third_party_settings: { }
type: entity_reference_label
region: content
links:
weight: 100
region: content
hidden:
field_guzzle_data_payload: true
field_guzzle_endpoint_url: true
field_guzzle_raw_headers: true
field_guzzle_request_method: true
langcode: en
status: true
dependencies:
config:
- field.storage.node.field_gnode_allow_arg_fwd
- node.type.guzzle_rest
id: node.guzzle_rest.field_gnode_allow_arg_fwd
field_name: field_gnode_allow_arg_fwd
entity_type: node
bundle: guzzle_rest
label: 'Allow guzzlenode arg forwarding'
description: 'Should we allow forwarding of arguments (&arg1=10&arg2=20 -> /10/20'
required: false
translatable: false
default_value:
-
value: 1
default_value_callback: ''
settings:
on_label: 'On'
off_label: 'Off'
field_type: boolean
langcode: en
status: true
dependencies:
config:
- field.storage.node.field_gnode_allow_head_fwd
- node.type.guzzle_rest
id: node.guzzle_rest.field_gnode_allow_head_fwd
field_name: field_gnode_allow_head_fwd
entity_type: node
bundle: guzzle_rest
label: 'Allow guzzlenode headers forwarding'
description: 'Forward headers of drupal call to the external call'
required: false
translatable: false
default_value:
-
value: 0
default_value_callback: ''
settings:
on_label: 'On'
off_label: 'Off'
field_type: boolean
langcode: en
status: true
dependencies:
config:
- field.storage.node.field_gnode_allow_param_fwd
- node.type.guzzle_rest
id: node.guzzle_rest.field_gnode_allow_param_fwd
field_name: field_gnode_allow_param_fwd
entity_type: node
bundle: guzzle_rest
label: 'Allow guzzlenode parameter forward'
description: 'Allow forward of parameters : param1_name=aaa&param1_value=bbb -> ?aaa=bbb'
required: false
translatable: false
default_value:
-
value: 0
default_value_callback: ''
settings:
on_label: 'On'
off_label: 'Off'
field_type: boolean
langcode: en
status: true
dependencies:
config:
- field.storage.node.field_gnode_allow_payload_fwd
- node.type.guzzle_rest
id: node.guzzle_rest.field_gnode_allow_payload_fwd
field_name: field_gnode_allow_payload_fwd
entity_type: node
bundle: guzzle_rest
label: 'Allow guzzlenode post data forwarding'
description: 'eg include drupal POST call body to the external call'
required: false
translatable: false
default_value:
-
value: 0
default_value_callback: ''
settings:
on_label: 'On'
off_label: 'Off'
field_type: boolean
langcode: en
status: true
dependencies:
config:
- field.storage.node.field_guzzlenode_call_limit
- node.type.guzzle_rest
id: node.guzzle_rest.field_guzzlenode_call_limit
field_name: field_guzzlenode_call_limit
entity_type: node
bundle: guzzle_rest
label: 'Call limit for this guzzlenode '
description: 'How many times should we allow this REST api to be called'
required: false
translatable: false
default_value:
-
value: 100
default_value_callback: ''
settings:
min: 0
max: 1000
prefix: ''
suffix: ''
field_type: integer
#custom field -for defining GUZZLENODE ACCESS per role
langcode: en
status: true
dependencies:
config:
- field.storage.node.field_guzzlenode_role_api_access
- node.type.guzzle_rest
id: node.guzzle_rest.field_guzzlenode_role_api_access
field_name: field_guzzlenode_role_api_access
entity_type: node
bundle: guzzle_rest
label: guzzlenode_role_api_access
description: 'ALSO Grant access to THIS guzzlenode API to the ROLES defined here'
required: false
translatable: false
default_value: { }
default_value_callback: ''
settings:
handler: 'default:user_role'
handler_settings: { }
field_type: entity_reference
#custom field -for defining GUZZLENODE ACCESS per USER
langcode: en
status: true
dependencies:
config:
- field.storage.node.field_guzzlenode_user_api_access
- node.type.guzzle_rest
id: node.guzzle_rest.field_guzzlenode_user_api_access
field_name: field_guzzlenode_user_api_access
entity_type: node
bundle: guzzle_rest
label: guzzlenode_user_api_access
description: 'ALSO Grant access to THIS guzzlenode API to the users defined here'
required: false
translatable: false
default_value: { }
default_value_callback: ''
settings:
handler: 'default:user'
handler_settings: { }
field_type: entity_reference
langcode: en
status: true
dependencies:
module:
- node
id: node.field_gnode_allow_arg_fwd
field_name: field_gnode_allow_arg_fwd
entity_type: node
type: boolean
settings: { }
module: core
locked: false
cardinality: 1
translatable: true
indexes: { }
persist_with_no_fields: false
custom_storage: false
langcode: en
status: true
dependencies:
module:
- node
id: node.field_gnode_allow_head_fwd
field_name: field_gnode_allow_head_fwd
entity_type: node
type: boolean
settings: { }
module: core
locked: false
cardinality: 1
translatable: true
indexes: { }
persist_with_no_fields: false
custom_storage: false
langcode: en
status: true
dependencies:
module:
- node
id: node.field_gnode_allow_param_fwd
field_name: field_gnode_allow_param_fwd
entity_type: node
type: boolean
settings: { }
module: core
locked: false
cardinality: 1
translatable: true
indexes: { }
persist_with_no_fields: false
custom_storage: false
langcode: en
status: true
dependencies:
module:
- node
id: node.field_gnode_allow_payload_fwd
field_name: field_gnode_allow_payload_fwd
entity_type: node
type: boolean
settings: { }
module: core
locked: false
cardinality: 1
translatable: true
indexes: { }
persist_with_no_fields: false
custom_storage: false
langcode: en
status: true
dependencies:
module:
- node
id: node.field_guzzlenode_call_limit
field_name: field_guzzlenode_call_limit
entity_type: node
type: integer
settings:
unsigned: false
size: normal
module: core
locked: false
cardinality: 1
translatable: true
indexes: { }
persist_with_no_fields: false
custom_storage: false
#custom field -for defining GUZZLENODE ACCESS per ROLE
langcode: en
status: true
dependencies:
module:
- node
- user
id: node.field_guzzlenode_role_api_access
field_name: field_guzzlenode_role_api_access
entity_type: node
type: entity_reference
settings:
target_type: user_role
module: core
locked: false
cardinality: -1
translatable: true
indexes: { }
persist_with_no_fields: false
custom_storage: false
#custom field -for defining GUZZLENODE ACCESS per USER
langcode: en
status: true
dependencies:
module:
- node
- user
id: node.field_guzzlenode_user_api_access
field_name: field_guzzlenode_user_api_access
entity_type: node
type: entity_reference
settings:
target_type: user
module: core
locked: false
cardinality: -1
translatable: true
indexes: { }
persist_with_no_fields: false
custom_storage: false
langcode: en
status: true
dependencies:
module:
- basic_auth
- d8_guzzlenode_rest
- hal
- serialization
- simple_oauth
- user
id: guzzlenode_rest_resource
plugin_id: guzzlenode_rest_resource
granularity: resource
configuration:
methods:
- GET
- POST
formats:
- hal_json
- json
authentication:
- basic_auth
- oauth2
- cookie
name: d8_guzzlenode_rest
type: module
description: D8 add REST exports to guzzlerestgenerator module . Example Url is http://example/myurlalias?_format=json&id1=3&param1=hello&param2=bye this will call external REST restpoint.com/hello/bye
description: D8 add REST exports to guzzlerestgenerator module (subrequest ready) . Example Url is http://example/myurlalias?_format=json&id1=3&param1=hello&param2=bye this will call external REST restpoint.com/hello/bye
core: 8.x
package: Custom
version: '8.x-0.5jon-2018021b'
version: '8.x-0.8jon-20180224a'
dependencies:
- guzzlerestgenerator
\ No newline at end of file
......@@ -8,7 +8,81 @@
use Drupal\Core\Routing\RouteMatchInterface;
/**
* Implements hook_help().
* Implements hook_rest_entity_form_alter(). ENABLE the 2 new guzzlenode fields
*/
function d8_guzzlenode_rest_form_alter(&$form, \Drupal\Core\Form\FormStateInterface $form_state, $form_id) {
\Drupal::entityTypeManager()
->getStorage('entity_form_display')
->load('node.guzzle_rest.default') //orig ->load('user.user.default')
->setComponent('field_guzzlenode_user_api_access'
/* , [
'type' => 'string',
'label' => 'above',
'settings' => ['link_to_entity' => 'false'],
]*/
)->save();
\Drupal::entityTypeManager()
->getStorage('entity_form_display')
->load('node.guzzle_rest.default') //orig ->load('user.user.default')
->setComponent('field_guzzlenode_role_api_access'
/* , [
'type' => 'string',
'label' => 'above',
'settings' => ['link_to_entity' => 'false'],
]*/
)->save();
// \Drupal::logger('DEBUG d8_guzzlenode_rest')->notice("jon CUSTOM entity_form_display "); //DEBUG
} // END of function d8_guzzlenode_rest_form_alter(&$form, \Drupal\Core\Form\FormStateInterface $form_state, $form_id) {
/**
* Implements hook_rest_entity_base_field_info(). CUSTOM field
*/
/*
function d8_guzzlenode_rest_entity_base_field_info(\Drupal\Core\Entity\EntityTypeInterface $entity_type) {
if ($entity_type
->id() == 'guzzle_rest') {
$fields = [];
$fields['guzzle_api_user_access'] = BaseFieldDefinition::create('entity_reference')
->setLabel(t('Users allowed'))
->setDescription(t('users that are allowed to access this External API'))
->setRevisionable(FALSE)
->setSetting('target_type', 'user')
->setSetting('handler', 'default')
->setCardinality(FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED)
->setTranslatable(FALSE)
->setDisplayOptions('view', [
'label' => 'hidden',
'type' => 'author',
'weight' => 0,
])
->setDisplayOptions('form', [
'type' => 'entity_reference_autocomplete',
'weight' => 5,
'settings' => [
'match_operator' => 'CONTAINS',
'size' => '60',
'autocomplete_type' => 'tags',
'placeholder' => '',
],
])
->setDisplayConfigurable('form', TRUE)
->setDisplayConfigurable('view', TRUE);
\Drupal::logger('DEBUG d8_guzzlenode_rest')->notice("jon CUSTOM FIELD CREATED "); //DEBUG
return $fields;
}
}
*/
/**
* Implements hook_help(). (auto-generated)
*/
function d8_guzzlenode_rest_help($route_name, RouteMatchInterface $route_match) {
switch ($route_name) {
......@@ -23,8 +97,10 @@ function d8_guzzlenode_rest_help($route_name, RouteMatchInterface $route_match)
}
}
/**
* Implements hook_theme().
* Implements hook_theme(). (auto-generated)
*/
function d8_guzzlenode_rest_theme() {
return [
......
# In my_module.permissions.yml file.
guzzlenode allow access to ext API guzzlenodes:
title: 'GuzzleREST - General access to external guzzleAPIs'
description: 'This is a general permission to be able to access ALL guzzlenodes/external APIs (but not use them - you will need to specify usernames/roles inside EACH guzzlenode). Note 1: this ENABLES/DISABLES everything for everyone.So, you MUST have this permission in order to do anything. Note 2: From "RESTful Web Services" you can further control access to Drupal GET,POST,PATCH REST points. The final check is done when you check if the current USERNAME is declared in the specific guzzlenode'
restrict access: TRUE
\ No newline at end of file
<?php
namespace Drupal\d8_guzzlenode_rest\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 = "guzzlenode_rest_resource",
* label = @Translation("Guzzlenode rest resource"),
* uri_paths = {
* "canonical" = "/api/relay"
* }
* )
*/
class GuzzlenodeRestResource extends ResourceBase {
/**
* A current user instance.
*
* @var \Drupal\Core\Session\AccountProxyInterface
*/
protected $currentUser;
/**
* Constructs a new GuzzlenodeRestResource 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;
}
/**