Request and Response introduction
Requests are the main instrument in enmeshed to interact with other Identities. They enable various business processes, e.g. creating, sharing or receiving Attributes, asking a peer for authentication or consent, and much more. Also, parts of a vaster business process can be implemented with them, like querying all personal information of a user to fill out a tax form.
Requests are unique between Identities and can only be processed once by a single Identity, even across multiple devices associated with them. Each Request can only have a single Response, which responds to the complete Request and contains all the information the requestor needs. The Request-Response flow allows to establish transactional behavior between Identities.
Requests
Structure of Requests
A Request can be created by an Identity and sent to a peer to exchange information with them. Specifying the exact demands to the peer, RequestItems are the core of the Request. In case multiple RequestItems should be answered jointly, e.g. to enhance the structure for the user, they can be combined to a RequestItemGroup. After creating the Request, it can be transmitted either via a RelationshipTemplate (see Requests via RelationshipTemplates) or via a Message (see Requests via Messages).
Types of RequestItems
To extinguish different scenarios how to use Requests, there are various types of RequestItems tailored to them.
AuthenticationRequestItem
With the AuthenticationRequestItem the Sender can request the peer for an authentication in a business context for a certain purpose. The peer can then decide to authenticate or not. This authentication is mostly short-lived and limited in time. Possible examples are:
- Authentication for a login to a website.
- Authentication for opening a door.
Depending on whether the AuthenticationRequestItem is to be accepted or rejected, its Recipient has different parameters to choose from for responding to it:
- To accept this RequestItem, the AcceptRequestItemParameters can be utilized.
- To reject this RequestItem, the RejectRequestItemParameters can be utilized.
After the Recipient has responded to the AuthenticationRequestItem, a suitable ResponseItem is generated and transferred to the Sender of the Request:
- After accepting this RequestItem, an AcceptResponseItem will be transferred.
- After rejecting this RequestItem, a RejectResponseItem will be transferred.
- In case of an error, an ErrorResponseItem will be transferred.
ConsentRequestItem
With the ConsentRequestItem it is possible to request the one-time consent of a peer to an arbitrary text and thus reach agreement on a certain non-machine-processable context. All details on how to use the ConsentRequestItem and examples of use cases for it can be found in the Request one-time consent of peer guide.
Note that the ConsentRequestItem cannot be used if intending to request persistent consent from a peer.
Depending on whether the ConsentRequestItem is to be accepted or rejected, its Recipient has different parameters to choose from for responding to it:
- To accept this RequestItem, the AcceptRequestItemParameters can be utilized.
- To reject this RequestItem, the RejectRequestItemParameters can be utilized.
After the Recipient has responded to the ConsentRequestItem, a suitable ResponseItem is generated and transferred to the Sender of the Request:
- After accepting this RequestItem, an AcceptResponseItem will be transferred.
- After rejecting this RequestItem, a RejectResponseItem will be transferred.
- In case of an error, an ErrorResponseItem will be transferred.
CreateAttributeRequestItem
If you want to create IdentityAttributes or RelationshipAttributes for the peer, the CreateAttributeRequestItem can be used. Please have a look at the ProposeAttributeRequestItem if the peer should be able to overwrite the Attribute. To create an Attribute with a fixed value defined by the Sender, an Identity uses the CreateAttributeRequestItem. A fixed value in this case means, that the Recipient is not allowed to change the value when accepting the Request. All details on how to use the CreateAttributeRequestItem and examples of use cases for it can be found in the Create Attributes for peer guide.
Depending on whether the CreateAttributeRequestItem is to be accepted or rejected, its Recipient has different parameters to choose from for responding to it:
- To accept this RequestItem, the AcceptRequestItemParameters can be utilized.
- To reject this RequestItem, the RejectRequestItemParameters can be utilized.
After the Recipient has responded to the CreateAttributeRequestItem, a suitable ResponseItem is generated and transferred to the Sender of the Request:
- After accepting this RequestItem, a CreateAttributeAcceptResponseItem will be transferred.
- After rejecting this RequestItem, a RejectResponseItem will be transferred.
- In case of an error, an ErrorResponseItem will be transferred.
DeleteAttributeRequestItem
If you want to request the deletion of an own Attribute from a peer, the DeleteAttributeRequestItem must be used.
Depending on whether the DeleteAttributeRequestItem is to be accepted or rejected, its Recipient has different parameters to choose from for responding to it:
- To accept this RequestItem, the AcceptDeleteAttributeRequestItemParameters can be utilized.
- To reject this RequestItem, the RejectRequestItemParameters can be utilized.
After the Recipient has responded to the DeleteAttributeRequestItem, a suitable ResponseItem is generated and transferred to the Sender of the Request:
- After accepting this RequestItem, a DeleteAttributeAcceptResponseItem will be transferred.
- After rejecting this RequestItem, a RejectResponseItem will be transferred.
- In case of an error, an ErrorResponseItem will be transferred.
FreeTextRequestItem
With the FreeTextRequestItem it is possible to send a free text to the peer. The peer itself can accept this with a free text as well.
Depending on whether the FreeTextRequestItem is to be accepted or rejected, its Recipient has different parameters to choose from for responding to it:
- To accept this RequestItem, the AcceptFreeTextRequestItemParameters can be utilized.
- To reject this RequestItem, the RejectRequestItemParameters can be utilized.
After the Recipient has responded to the FreeTextRequestItem, a suitable ResponseItem is generated and transferred to the Sender of the Request:
- After accepting this RequestItem, a FreeTextAcceptResponseItem will be transferred.
- After rejecting this RequestItem, a RejectResponseItem will be transferred.
- In case of an error, an ErrorResponseItem will be transferred.
ProposeAttributeRequestItem
The ProposeAttributeRequestItem is a combination of a ReadAttributeRequestItem and a CreateAttributeRequestItem. The Sender would like to receive a correct Attribute from the peer, thinks it has a possible value but the peer might overrule this value with an existing or new one. To create an Attribute with a value proposed by the Sender, an Identity uses the ProposeAttributeRequestItem. A proposed value in this case means, that the Recipient is allowed to change the value if accepting the Request. All details on how to use the ProposeAttributeRequestItem and examples of use cases for it can be found in the Propose Attributes to peer guide.
Depending on whether the ProposeAttributeRequestItem is to be accepted or rejected, its Recipient has different parameters to choose from for responding to it:
- To accept this RequestItem, the AcceptProposeAttributeRequestItemParameters can be utilized.
- To reject this RequestItem, the RejectRequestItemParameters can be utilized.
After the Recipient has responded to the ProposeAttributeRequestItem, a suitable ResponseItem is generated and transferred to the Sender of the Request:
- After accepting this RequestItem with a new Attribute or an existing one that isn’t shared with the peer already neither itself nor any of its predecessing versions, a ProposeAttributeAcceptResponseItem will be transferred.
- After accepting this RequestItem with an existing Attribute that was shared with the peer already, an AttributeAlreadySharedAcceptResponseItem will be transferred, given that the own shared LocalAttribute doesn’t have
"DeletedByPeer"
or"ToBeDeletedByPeer"
asdeletionInfo.deletionStatus
. - After accepting this RequestItem with an existing Attribute of which a predecessor was shared with the peer already, an AttributeSuccessionAcceptResponseItem will be transferred, given that the own shared predecessor doesn’t have
"DeletedByPeer"
or"ToBeDeletedByPeer"
asdeletionInfo.deletionStatus
. - After rejecting this RequestItem, a RejectResponseItem will be transferred.
- In case of an error, an ErrorResponseItem will be transferred.
ReadAttributeRequestItem
If you want to query an Identity’s Attributes this is done with the ReadAttributeRequestItem. To query Attributes which are not known to the Sender, an Identity uses the ReadAttributeRequestItem. All details on how to use the ReadAttributeRequestItem and examples of use cases for it can be found in the Read Attributes from peer guide.
Depending on whether the ReadAttributeRequestItem is to be accepted or rejected, its Recipient has different parameters to choose from for responding to it:
- To accept this RequestItem, the AcceptReadAttributeRequestItemParameters can be utilized.
- To reject this RequestItem, the RejectRequestItemParameters can be utilized.
After the Recipient has responded to the ReadAttributeRequestItem, a suitable ResponseItem is generated and transferred to the Sender of the Request:
- After accepting this RequestItem with a new Attribute or an existing one that isn’t shared with the peer already neither itself nor any of its predecessing versions, a ReadAttributeAcceptResponseItem will be transferred.
- After accepting this RequestItem with an existing Attribute that was shared with the peer already, an AttributeAlreadySharedAcceptResponseItem will be transferred, given that the own shared LocalAttribute doesn’t have
DeletedByPeer
asdeletionInfo.deletionStatus
. - After accepting this RequestItem with an existing Attribute of which a predecessor was shared with the peer already, an AttributeSuccessionAcceptResponseItem will be transferred, given that the own shared predecessor doesn’t have
"DeletedByPeer"
or"ToBeDeletedByPeer"
asdeletionInfo.deletionStatus
. - After rejecting this RequestItem, a RejectResponseItem will be transferred.
- In case of an error, an ErrorResponseItem will be transferred.
RegisterAttributeListenerRequestItem
This item is used to register a Listener for a specific Attribute. The Listener will create a Request in status Draft
if an Attribute was created that matches the given query and the user is able to send the Request to the creator of the RegisterAttributeListenerRequestItem. Possible examples are:
- Asking for a specific RelationshipAttribute of a partner organization.
Depending on whether the RegisterAttributeListenerRequestItem is to be accepted or rejected, its Recipient has different parameters to choose from for responding to it:
- To accept this RequestItem, the AcceptRequestItemParameters can be utilized.
- To reject this RequestItem, the RejectRequestItemParameters can be utilized.
After the Recipient has responded to the RegisterAttributeListenerRequestItem, a suitable ResponseItem is generated and transferred to the Sender of the Request:
- After accepting this RequestItem, a RegisterAttributeListenerAcceptResponseItem will be transferred.
- After rejecting this RequestItem, a RejectResponseItem will be transferred.
- In case of an error, an ErrorResponseItem will be transferred.
ShareAttributeRequestItem
If you want to share the own DisplayName and possibly other Attributes this is done with the ShareAttributeRequestItem. To share own IdentityAttributes (owner = self) an Identity uses the ShareAttributeRequestItem. The Identity needs to create the IdentityAttribute separately before the Attribute can be shared. All details on how to use the ShareAttributeRequestItem and examples of use cases for it can be found in the Share Attributes with peer guide.
Depending on whether the ShareAttributeRequestItem is to be accepted or rejected, its Recipient has different parameters to choose from for responding to it:
- To accept this RequestItem, the AcceptRequestItemParameters can be utilized.
- To reject this RequestItem, the RejectRequestItemParameters can be utilized.
After the Recipient has responded to the ShareAttributeRequestItem, a suitable ResponseItem is generated and transferred to the Sender of the Request:
- After accepting this RequestItem, a ShareAttributeAcceptResponseItem will be transferred.
- After rejecting this RequestItem, a RejectResponseItem will be transferred.
- In case of an error, an ErrorResponseItem will be transferred.
Rendering of RequestItems
Please note that the rendering of the RequestItems in the App is currently being revised. As soon as the changes to the App have been made, the example here will also be adapted.
This section gives an example of a Request that contains various RequestItems, namely an AuthenticationRequestItem, a ConsentRequestItem, a CreateAttributeRequestItem, a FreeTextRequestItem, a ProposeAttributeRequestItem, a ReadAttributeRequestItem, a RegisterAttributeListenerRequestItem and a ShareAttributeRequestItem, within its items
property. This Request can be sent from a Sender to an App user. A screenshot from the App showing how the Request is displayed to the App user is provided afterwards.
{
"title": "<title of Request>",
"description": "<description of Request>",
"items": [
{
"@type": "AuthenticationRequestItem",
"mustBeAccepted": true,
"title": "<title of AuthenticationRequestItem>",
"description": "<description of AuthenticationRequestItem>"
},
{
"@type": "ConsentRequestItem",
"mustBeAccepted": true,
"title": "<title of ConsentRequestItem>",
"description": "<description of ConsentRequestItem>",
"consent": "<consent issue originating from the Sender>",
"link": "<link to external website with more information on the issue>"
},
{
"@type": "CreateAttributeRequestItem",
"mustBeAccepted": true,
"title": "<title of CreateAttributeRequestItem>",
"description": "<description of CreateAttributeRequestItem>",
"attribute": {
"@type": "IdentityAttribute",
"owner": "",
"value": {
"@type": "Surname",
"value": "<surname created for the App user by the Sender>"
},
"tags": ["<tag of surname to be created>"],
"validFrom": "<start of IdentityAttribute's validity>",
"validTo": "<end of IdentityAttribute's validity>"
}
},
{
"@type": "FreeTextRequestItem",
"mustBeAccepted": false,
"title": "<title of FreeTextRequestItem>",
"description": "<description of FreeTextRequestItem>",
"freeText": "<free text written by the Sender>"
},
{
"@type": "ProposeAttributeRequestItem",
"mustBeAccepted": false,
"title": "<title of ProposeAttributeRequestItem>",
"description": "<description of ProposeAttributeRequestItem>",
"attribute": {
"@type": "IdentityAttribute",
"owner": "",
"value": {
"@type": "GivenName",
"value": "<given name proposed by the Sender>"
},
"tags": ["<tag of proposed given name>"],
"validFrom": "<start of IdentityAttribute's validity>",
"validTo": "<end of IdentityAttribute's validity>"
},
"query": {
"@type": "IdentityAttributeQuery",
"valueType": "GivenName"
}
},
{
"@type": "ReadAttributeRequestItem",
"mustBeAccepted": false,
"title": "<title of ReadAttributeRequestItem>",
"description": "<description of ReadAttributeRequestItem>",
"query": {
"@type": "IdentityAttributeQuery",
"valueType": "BirthDate",
"tags": ["<tag of date of birth to be read>"],
"validFrom": "<start of IdentityAttribute's validity>",
"validTo": "<end of IdentityAttribute's validity>"
}
},
{
"@type": "RegisterAttributeListenerRequestItem",
"mustBeAccepted": false,
"title": "<title of RegisterAttributeListenerRequestItem>",
"description": "<description of RegisterAttributeListenerRequestItem>",
"query": {
"@type": "IdentityAttributeQuery",
"valueType": "StreetAddress",
"tags": ["<tag of street address for which the registration was made>"],
"validFrom": "<start of IdentityAttribute's validity>",
"validTo": "<end of IdentityAttribute's validity>"
}
},
{
"@type": "ShareAttributeRequestItem",
"mustBeAccepted": true,
"title": "<title of ShareAttributeRequestItem>",
"description": "<description of ShareAttributeRequestItem>",
"attribute": {
"@type": "IdentityAttribute",
"owner": "<address of Sender>",
"value": {
"@type": "DisplayName",
"value": "<display name shared by the Sender>"
},
"tags": ["<tag of shared display name>"],
"validFrom": "<start of IdentityAttribute's validity>",
"validTo": "<end of IdentityAttribute's validity>"
},
"sourceAttributeId": "<ID of source RepositoryAttribute>"
}
]
}
The <...>
notation is used as a placeholder for the actual data as usual. Also note that in the example Request, the IdentityAttributes have been used for test purposes instead of the RelationshipAttributes for those RequestItems that relate to Attributes. For an overview of the different types of Attributes, consult the Attribute introduction.
After the Sender has created the Request and sent it to the App user via a Message or via a RelationshipTemplate, the Request is displayed to the App user. The following screenshot shows the rendering of the example Request in the App. The order in which the RequestItems are rendered corresponds to the order in which they appear in the example Request.
At the bottom of the App screen, there is a “Reject” button to reject the Request and an “Accept” button to accept the Request. If no Relationship has been established between the Sender and the App user, and the Request was sent via a RelationshipTemplate, the “Accept” button is labeled “Add Contact” instead.
The screenshot demonstrates that the rendering of the individual kinds of RequestItems differs from one another. However, the display of a RequestItem in the App depends not only on its properties, but also on which DecideRequestItemParameters must be used to accept it.
For instance, when accepting a ProposeAttributeRequestItem, the AcceptProposeAttributeRequestItemParameters must be utilized. These parameters enable acceptance of the ProposeAttributeRequestItem with either an existing Attribute or a new one, which could be the Attribute proposed by the Sender. In the App, a small arrow icon is displayed to the right of the ProposeAttributeRequestItem, which leads the App user to a list of existing Attributes that would be suitable for accepting the ProposeAttributeRequestItem, too. In addition, further new Attributes suitable for accepting the ProposeAttributeRequestItem can be created there.
In principle, a RequestItem can not only be accepted, but also rejected, for which the RejectRequestItemParameters are used.
The App user can reject a RequestItem by unticking the checkbox to its left, and accept it by ticking the checkbox.
However, any RequestItem whose value of the property mustBeAccepted
is set to true
must be accepted and cannot be rejected.
In the App, this is shown by a ticked and greyed-out checkbox, indicating that the RequestItem cannot be rejected.
In our example Request, this is the case for the AuthenticationRequestItem, the ConsentRequestItem, the CreateAttributeRequestItem and the ShareAttributeRequestItem.
If you do not agree to accept a RequestItem whose value of its mustBeAccepted
property is set to true
, you are forced to reject the Request as a whole.
Some RequestItems exhibit particular characteristics.
For the ConsentRequestItem, for example, a link
to an external website with more information on the consent
issue originating from the Sender can optionally be specified.
Specifying a link
causes an icon to appear to the right of the ConsentRequestItem.
Clicking on this icon redirects to the corresponding website.
The ConsentRequestItem from our example Request provides a link
. For this reason, the mentioned icon can be found in the screenshot of the App.
Responses
Structure of Responses
Once the other Identity receives a Request, they can decide whether to accept or reject it. Then, a Response will be created, containing a ResponseItem or ResponseItemGroup for every RequestItem or RequestItemGroup, respectively. The kind of ResponseItem depends on the decision of the Recipient, as well as on the kind of RequestItem.
Types of ResponseItems
There are three different categories of ResponseItems. If a RequestItem is accepted, an AcceptResponseItem will be created. Depending on the kind of RequestItem, it might be a specific AcceptResponseItem, extending the base AcceptResponseItem to answer to RequestItems demanding additional information. For example, a ReadAttributeRequestItem is accepted using a ReadAttributeAcceptResponseItem, additionally transmitting information about the respective Attribute.
If a RequestItem is rejected, however, a RejectResponseItem is created. Lastly, in case the enmeshed Runtime detects a problem, an ErrorResponseItem is generated. It will never be created manually.
Request-Response flow
LocalRequests and LocalResponses
Requests and Responses as discussed above refer to the data structures that are exchanged between Identities. Locally, each Identity stores them in LocalRequests and LocalResponses. Note that the LocalResponse is stored within the respective LocalRequest, besides properties that are common for both peers like the LocalRequestStatus and others that are distinct for each Identity, e.g. the address of the peer or whether the Request was sent by you or received from the peer.
Sending Requests via Messages
Requests can only be send via Message, if you already have an active Relationship with the Recipient. Otherwise, you need to utilize a RelationshipTemplate.
If you want to send a Request via Message, firstly you need to create a LocalRequest.
Its ID equals the one of the associated Request that is sent in a Message to your peer.
If the peer accepts the Request and reponds to it, at their side a LocalRequest will be created, having the same ID, however, opposite values for the fields peer
and isOwn
.
Also, a LocalResponse will be created and stored directly within the LocalRequest.
Then, a Message will transfer the Response wrapped in a ResponseWrapper back to you, where it can be mapped to your initially created LocalRequest.
You can find an example for the Request-Response flow via Message below.
Sending Requests via RelationshipTemplates
If you don’t have a Relationship with the Recipient yet, the Request needs to be formulated within the onNewRelationship
property of the RelationshipTemplateContent.
Otherwise, utilize the onExistingRelationship
property.
Alternatively, you can transfer Requests via RelationshipTemplates.
To do so, you locally create the RelationshipTemplate and in the process the Request, however, no LocalRequest will be created, yet.
Hence, the Request your peer receives also doesn’t have an ID, yet.
Now, there are two possibilities: either you already have a Relationship with the peer or you wish to establish one, given the condition the peer accepts your Request.
For this, you formulate the Request in the content.onExistingRelationship
or the content.onNewRelationship
property of the RelationshipTemplate, respectively.
Note, however, that the content.onNewRelationship
property is required and, therefore, must always be set, in order to avoid unstable behavior, if someone you don’t have a Relationship with opens the RelationshipTemplate.
Firstly, let’s consider the case you already have a Relationship with the peer.
Receiving your RelationshipTemplate, thus, at their side the content.onExistingRelationship
property will be processed, containing your Request.
If the peer decides to accept and to respond to the Request, a LocalRequest will be created, comprising the LocalResponse.
Its content, i.e. the Response, is wrapped in a ResponseWrapper and sent via Message back to you.
Only now, a LocalRequest at your side will be created, having the same ID like its counterpart at your peer’s side, since it was transmitted within the Response.
Also, the LocalResponse is stored directly within the LocalRequest, so that the LocalRequest you just created already has the status accepted
.
In case you don’t have a Relationship with the peer yet, opening the RelationshipTemplate, its content.onNewRelationship
property will be processed.
If the peer decides to accept and to respond to your Request, again a LocalRequest and LocalResponse will be created at their side.
However, the returned data differ.
Instead of a ResponseWrapper inside a Message, a Relationship is returned which is in the status pending
for now.
It contains the RelationshipTemplate, as well as the Response to the Request.
Only after you accept the Relationship, the LocalRequest with LocalResponse is created at your side and the peer will receive the information about the status change via a consumption.incomingRequestStatusChanged
event.
You can find an example for the Request-Response flow via RelationshipTemplate below.
Examples
Working with required and optional RequestItems
An organization has a Relationship with a customer and needs their consent to the privacy terms.
Additionally, the organization would like to know, if the customer is interested in optionally receiving a newsletter.
Thus, they send a Request via Message, containing two ConsentRequestItems.
On the one hand, the RequestItem regarding consent to the Privacy Terms has the mustBeAccepted
flag enabled, indicating that the Request can’t be accepted without accepting this item.
On the other hand, the RequestItem regarding the Newsletter has the mustBeAccepted
flag disabled.
Hence, the customer can freely choose whether or not they would like to give their consent to it.
Let’s consider the case the Request and, therefore, the privacy terms are accepted, but the consent to the newsletter is denied.
The resulting Request-Response flow is depicted in the following graphic.
For simplicity some properties are omitted.
Working with RequestItemGroups
At a job fair a company wants to offer a convenient way to get in touch with interested jobseekers.
For this, they provide a QR code, linking to a RelationshipTemplate.
In its content.onNewRelationship
property it holds a Request with two RequestItemGroups.
One of them contains Attributes the company shares with the peer, e.g. the company name.
The other contains Attributes it would like to query from the peer.
In this example they are the given and surname and optionally an email address, following the Integration example.
Now, an interested person can scan the QR code, provide their information and send their Response inside a Relationship’s creation content.
Once the company accepts the new Relationship, they can exchange Messages or other data using enmeshed.