Base Entities
Base Entities are basic resource entities intended to be (re-)usable in a wide range of applications and environments. They have a minimal set of core attributes and can easily be extended to fit the needs of a particular application.
The Relay API Gateway provides a growing set of Base Entities, such as
Bundle Structure
Base Entity Bundles
Base Entities have a corresponding bundle where they are defined (e.g. the Base Organization Bundle). These Base Entity Bundles define
- the Base Entity
- HTTP endpoints to request the Base Entity (at least one item and one collection endpoint)
- the Base Entity Provider Interface, which declares Base Entity access methods (at least one getter for an item and for a collection)
Base Entity Connector Bundles
The Base Entity Provider Interface is usually implemented in a so-called Base Entity Connector Bundle retrieving Base Entity data from a backend system, such as a local database, the CAMPUSOnline API, LDAP, or other sources.
There may exist multiple Connector Bundles (Provider Interface implementations) per Base Entity, but only one per installation.
How to Extend Base Entities
Base Entities may lack some attributes required by your business logic. Local Data provides a mechanism to extend Base Entities by attributes which are not part of the core attributes.
Adding Local Data Attributes to Existing Entities
To be able to request a new Local Data attribute, you need to add an entry to the local_data
node
of the Base Entity's bundle config:
dbp_relay_base_person:
local_data:
- local_data_attribute: foo
authorization_expression: 'user.get("MAY_READ_FOO")'
- local_data_attribute: bar
authorization_expression: 'true'
The authorization_expression
represents a conditional statement determining which users are authorized to read the attribute.
With the example config above, users with the MAY_READ_FOO
attribute may request the foo
attribute and
all users may request the bar
attribute of a person. See Access Control Policies to
learn how to write these expressions.
To add Local data to an entity you can write a custom Base Entity post event subscriber listening to the post event of the base entity, which is triggered after the entity data is retrieved from the backend:
class PersonPostEventSubscriber implements EventSubscriberInterface
{
public static function getSubscribedEvents(): array
{
return [
PersonPostEvent::class => 'onPost',
];
}
public function onPostEvent(PersonPostEvent $event)
{
$sourceData = $event->getSourceData();
$event->trySetLocalDataAttribute('foo', $sourceData['foo']);
if ($event->isLocalDataAttributeRequested('bar')) {
$bar = $externalApi->getBar(); // expensive api call
$event->setLocalDataAttribute('bar', $bar);
}
}
}
LocalDataPostEvent
and provide a getSourceData()
and a getEntity()
method by convention,
where
getSourceData()
provides the full set of available attributes for the entity.getEntity()
provides the entity itself.
To set local data attributes:
- If you have the attribute value already at hand, call
trySetLocalDataAttribute
. It is safe because it sets the value only if the attribute was requested and not yet set by another event subscriber. - If getting the attribute value is expensive, call
setLocalDataAttribute
only ifisLocalDataAttributeRequested
istrue
, i.e. if the attribute was actually requested and not yet set.
Note that local data values have to be serializable to JSON.
To learn how to add the Local Data mechanism to your own entity, see Local Data Aware Entities.
Local Data Mapping Config
Base Entity Connector Bundles in the Relay API Gateway ship with a built-in Base Entity event subscriber
(derived from LocalDataEventSubscriber
). It can be used by configuring the local_data_mapping
node
in the connector's bundle config:
dbp_relay_base_person_connector_ldap:
local_data_mapping:
- local_data_attribute: foo
source_attribute: foo_source
- local_data_attribute: fooList
source_attribute: foo_source
is_array: true # default: false
The example config above maps the source data attribute foo_source
to the Local Data attribute foo
. If
source attribute is not available null
is returned. The attribute fooList
is configured to be an array,
which means that the value of the source attribute is converted to a single-element array if it has a scalar value.
Conversely, if the attribute is not configured to be an array (which is the default) and the source attribute value
is of type array, the first array element is returned.
Local Data requests
Local data can be requested by clients using the includeLocal
parameter provided by Base Entity GET operations.
Its value is a comma-separated list of attribute names:
includeLocal=<attributeName>,...
The server will return a client error if
- The format of the
includeLocal
parameter value is invalid. - A requested attribute could not be provided by any event subscriber.
The server will issue a warning if
- Multiple event subscribers tried to set the same requested attribute.
Using Local Query Parameters
Base Entities usually provide basic filtering by their core attributes. Local Query parameters provide a mechanism to query by Local Data attributes for a specific connector backend which provides the data (LDAP, DB, ...).
To be able to query by a Local Data attribute, the allow_query
option of the attribute must be set to true
in the local_data
config of the Base Entity's bundle config:
dbp_relay_base_person:
local_data:
- local_data_attribute: foo
authorization_expression: 'user.get("MAY_READ_FOO")'
allow_query: true
Local Queries can be 'injected' by modifying the options passed to the connector backend. You can do this by writing a custom Base Entity pre event subscriber, listening to the pre event of the base entity , which is triggered before the query is executed:
class PersonPreEventSubscriber implements EventSubscriberInterface
{
public static function getSubscribedEvents(): array
{
return [
PersonPreEvent::class => 'onPreEvent',
];
}
public function onPreEvent(PersonPreEvent $preEvent)
{
$value = null;
if ($preEvent->tryPopPendingQueryParameter('foo', $value)) {
$options = $preEvent->getOptions();
$options['filter'] = [
'attribute' => 'foo',
'value' => $value,
];
$preEvent->setOptions($options);
}
}
}
Base Entity pre events in the Relay API Gateway are derived from LocalDataPreEvent
and provide the
following methods:
tryPopPendingQueryParameter(string $queryParameterName, &$queryParameterValue = null): bool
: Returnstrue
if the given parameter was requested by the client,false
otherwise. If requested, it acknowledges the parameter (i.e. tells, that it will handle the parameter) and provides its value.getPendingQueryParameters(): array
Returns the list of requested query parameters as key (attribute name) value (attribute value) pairs.getOptions(): array
Returns the list of options for the data providing connector backend.setOptions(array $options)
Set the list of (modified) options for the data providing connector backend.
Note that the built-in event subscriber described in Local Data Mapping Config can also be used to allow local queries.
Local Query Requests
Local Query parameters can be specified by clients using the queryLocal
parameter provided by Base Entity GET
operations. The format of the queryLocal
parameter is a comma-seperated list of
<parameter key>:<parameter value>
pairs, where <parameter value>
must be URL encoded:
queryLocal=<parameterName>:<parameterValue>,...
The server will return a client error if
- The format of the
queryLocal
parameter value is invalid. - A requested query parameter was not acknowledged by any event subscriber.