External extensions
It is expected that the reader of this article is familiar with the concepts of External Extensions as described in the Concepts Section.
The External Extensions are registered as External Endpoints that that are used by ShareAspace when making HTTP requests to the External Extensions.
From a customization point of view, these Extension would mainly be used for building custom:
- SharePackage validations
- Maturity System validations
- Custom logic for managing Events
- Custom DataExchange External Tasks that would typically be used for custom data mappers
- Integrations to third party software for retrieving event information
- Custom ShareAspace Web modules
- Custom ShareAspace Web components
- Custom ShareAspace Web forms
- Custom action based on ribbon menu clicks in ShareAspace Web modules
- Custom allowed properties service for the PropertyValueSet UI control
- Name value list
It is also possible to create custom implementations of ShareAspace components like the File Preview, Email component, Full-text indexing/search, and Event logging, these are however not described in this documentation.
Note
ShareAspace expect to get HTTP Status Codes 200
or 201
back from the externa service provided everything went well.
Important
Once ShareAspace has received a status code indicating success ShareAspace no longer takes responsibility of logging anything that goes on on the External Service. e.g. an Event in ShareAspace has triggered a long running process on an External Service. For this long running process. The External Service should not wait with the reply to ShareAspace till it is done processing. Instead the External Service should acknowledge that the message was received and then start executing the long running process. By doing this the External Service takes over the responsibility of handling any logging, retries or rescheduling of these long running processes. It is not possible for ShareAspace to resend an Event once the External Service has acknowledged that the message was received.
Error handling
Transient HTTP error
In ShareAspace a transient error is identified as follows.
- Connection error: it is not possible to connect to the extension.
- Request response with status code:
- Network failures (as HttpRequestException).
- HTTP 5XX status codes (server errors).
- HTTP 408 status code (request timeout).
If any of the above is true ShareAspace will see the failure as transient and will retry depending on the policy configuration for the extension (more on this in each extension type chapter).
Backoff strategy
If a transient error happens, ShareAspace will use a backoff strategy for its retry policy. The backoff policy used by ShareAspace is exponential up to 5 minutes. After 5 minutes ShareAspace will retry once every 5 minutes.
Logging
When an extension exceeds its allotted request limit the following event is logged as informational.
External Email extension ScenarioEmail exceeded its allotted request limit 100 calls in 00:01:00.
When a transient HTTP connection error happens the following event is logged.
HTTP transient error in call to external Email extension ScenarioEmail we will wait for 00:00:02 and try again, retry 1 of 5.
When a transient HTTP response status code happens the following event is logged.
HTTP transient error with status code BadGateway in call to external Email extension ScenarioEmail we will wait for 00:00:02 and try again, retry 1 of 5.
When a transient HTTP connection error happens for a retry forever request.
HTTP transient error in call to external Email extension ScenarioEmail we will wait for 00:00:02 and try again, retry 1 of ∞.
When a transient HTTP response status code happens for a retry forever request.
HTTP transient error with status code BadGateway in call to external Email extension ScenarioEmail we will wait for 00:00:02 and try again, retry 1 of ∞.
When a request timeout occurs the following event is logged.
Timeout when calling external Email extension ScenarioEmail after waiting 00:01:40.
When an event is removed from the event bus queue the following event is logged.
Failed to send event 3 from OnPartCreate on behalf of oem.sa@eurostep.com to recipient ScenarioEmail. The event is now removed from the queue.
When an event has been deleted by a user and it resulting in a event cancellation.
The event 1 has been deleted by the user and has now been canceled.
External endpoint
The External Endpoint is the simplest type of Endpoints that can be registered. ShareAspace can use this type of Endpoints for managing events or for allowing the use of custom External UI Modules within the ShareAspace Web application. ShareAspace cannot pass on an access token for impersonation to an endpoint like this.
Register
Using the ShareAspace Admin REST API, a Collection Administrator can register the Endpoint.
Tip
The Collection Administrator UI can also be used to register these. See the User Guide.
POST http://{FQDN}/api/admin/externalEndpoint
Content-Type: application/json
Body:
{
"url": "https://xyz.eurostep.com/endpoint",
"active": true,
"id": "myEndpoint",
"name": "the name of endpoint",
"description": "This is the description",
"method": "POST",
"category": "Event",
"requestTimeout": 600,
"retryForever": false,
"rateLimitNumberOfExecutions": 5,
"headers": [
{
"name": "content-type",
"value": "application/json"
}
]
}
Properties:
Name | Required | Type | Details | |
---|---|---|---|---|
url |
Yes | string |
The URL to the to the external endpoint. This URL is used by ShareAspace when calling the endpoint. | |
active |
bool |
To activate/deactivate the Extension. If no value is provided, it will default to true . It is possible to enable/disable an endpoint at runtime. |
||
id |
Yes | string |
The id of the endpoint. This id will be used when configuring subscriptions to use this endpoint. | |
name |
string |
The name of the endpoint. | ||
description |
string |
The description of the endpoint. | ||
method |
Yes | string |
The HTTP Method that ShareAspace should use when calling the endpoint. | |
category |
Yes | string |
The category of the extension. The category is like a tag. The ShareAspace subscription UI will use this category to help the user configuring a subscription. | |
requestTimeout |
int |
Default 100 seconds. | The time that ShareAspace will wait for a response from the endpoint. | |
retryForever |
bool |
Default false. If set to true ShareAspace will keep retrying the request indefinitely if there is a transient HTTP error reported by the endpoint. If the error is not identified as a transient error the request will not be retried but instead failed and logged. | ||
rateLimitNumberOfExecutions |
int |
Default 5. The number of request executions ShareAspace should allow in the timespan of 1 minute before all request to the endpoint are paused for 1 minute. Incoming requests are queued and will be delivered when there is resources enough to continue. | ||
headers |
Yes | array |
The request headers to set on the request to the endpoint. The content-type must be defined, other than that, these would typically manage API keys for the external service. |
Using the endpoint
If the HTTP method is set to POST
, PATCH
, or PUT
ShareAspace will
include a body when calling the endpoint. For this type of endpoint there
is however no predefined interface for this body, i.e. when you configure the
use of this type of endpoint you are in full control over the body. This means
that the body could be JSON, HTML, plain text, etc.
Default values transient HTTP error
- Timeout 100 seconds
- 5 retries on transient HTTP error [ 2 sec, 4 sec, 8 sec, 16 sec, 32 sec ]
Trusted external endpoint
The Trusted External Endpoint is similar to the External Endpoint in the sense
that you have full control over the contract for the external service. The difference
is that with the Trusted External Endpoint ShareAspace will pass a JWT
access token to
the external service. This access token will impersonate a ShareAspace user. This could
be the user that triggered an event or the user that owns the subscription that called
the external service.
Register
Using the ShareAspace Admin REST API, a Collection Administrator can register the Endpoint.
Tip
The Collection Administrator UI can also be used to register these. See the User Guide.
POST http://{FQDN}/api/admin/trustedExternalEndpoint
Content-Type: application/json
Body:
{
"url": "https://xyz.eurostep.com/trustedendpoint",
"tokenLifeTime": 15,
"active": true,
"id": "myTrustedEndpoint",
"name": "the name of endpoint",
"description": "This is the description",
"method": "POST",
"category": "Event",
"requestTimeout": 600,
"retryForever": false,
"rateLimitNumberOfExecutions": 5,
"headers": [
{
"name": "content-type",
"value": "application/json"
}
],
"permissions": {
"permissions": [
"TaskUploadAPI",
"AdministrationAPI"
],
"tokenCallback": "https://xyz.eurostep.com/trustedendpoint/callback"
}
}
Properties:
Name | Required | Type | Details | |
---|---|---|---|---|
url |
Yes | string |
The URL to the to the external endpoint. This URL is used by ShareAspace when calling the endpoint. | |
tokenLifeTime |
Yes | int |
The time, in minutes, that the JWT access token will be valid for. This token cannot be refreshed. |
|
active |
bool |
To activate/deactivate the Extension. If no value is provided, it will default to true . It is possible to enable/disable an endpoint at runtime. |
||
id |
Yes | string |
The id of the endpoint. This id will be used when configuring subscriptions to use this endpoint. | |
name |
string |
The name of the endpoint. | ||
description |
string |
The description of the endpoint. | ||
method |
Yes | string |
The HTTP Method that ShareAspace should use when calling the endpoint. | |
category |
Yes | string |
The category of the extension. The category is like a tag. The ShareAspace subscription UI will use this category to help the user configuring a subscription. | |
requestTimeout |
int |
Default 100 seconds. | The time that ShareAspace will wait for a response from the endpoint. | |
retryForever |
bool |
Default false. If set to true ShareAspace will keep retrying sending the message indefinitely if there is a transient HTTP error reported by the endpoint. | ||
rateLimitNumberOfExecutions |
int |
Default 5. The number of request executions ShareAspace should allow in the timespan of 1 minute before all request to the endpoint are paused for 1 minute. Incoming requests are queued and will be delivered when there is resources enough to continue. | ||
headers |
Yes | array |
The request headers to set on the request to the endpoint. The content-type must be defined, other than that, these would typically manage API keys for the external service. | |
permissions |
No | object |
Holds the configuration for requested permissions of the extension. Activating the permissions makes it possible for the extension to retrieve ShareAspace API keys (non-user-impersonating keys). These keys are rotated every 24hrs . Once configured the extension can request the keys using the ShareAspace API. ShareAspace will respond with the keys using a POST request to the configured tokenCallback address. |
Permissions:
API Key | Description |
---|---|
TaskUploadAPI |
Used for installing internal DataExchange tasks. |
AuthorizationAPI |
Used for managing ShareAspace internal user accounts. |
AdministrationAPI |
Used for managing a ShareAspace collection as a non authorized collection administrator. |
SnapshotAPI |
Used for creating and restoring ShareAspace snapshots. |
LicenseCommunicationAPI |
Used for managing the ShareAspace license. |
Using the endpoint
If the HTTP method is set to POST
, PATCH
, or PUT
ShareAspace will
include a body when calling the endpoint. For this type of endpoint there
is however no predefined interface for this body, i.e. when you configure the
use of this type of endpoint you are in full control over the body. This means
that the body could be JSON, HTML, plain text, etc.
For all requests to a Trusted External Endpoint, ShareAspace will append a
query parameter to the configured endpoint URL. This query parameter is named
access_token
and the value of this parameter is the issued JWT
access token.
Example:
POST https://xyz.eurostep.com/trustedendpoint?access_token=ey2234324...
Content-Type: application/json
Note
If the registered URL already contains query parameters, ShareAspace will just append this additional query parameter.
Requesting API key
POST https://{FQDN}/api/collection/externalExtension/acquireAccessToken/{extensionId}
Content-Type: application/json
{
"tokenCallback": "https://{FQDN}/callback",
"permissions": [
"TaskUploadAPI",
"AdministrationAPI
]
}
Response at callback:
POST {tokenCallback}
Content-Type: application/json
{
"AuthorizationAPI": {
"apiKey": "{apiKey}"
},
"TaskUploadAPI": {
"apiKey": "{apiKey}"
}
}
Note
That the tokenCallback
must match what is configured on the trusted external endpoint. Only the permissions defined on the trusted external end point can be requested.
Default values transient HTTP error
- Timeout 100 seconds
- 5 retries on transient HTTP error [ 2 sec, 4 sec, 8 sec, 16 sec, 32 sec ]
ShareAspace Extensions
Compared to the External Endpoint and Trusted External Endpoint the ShareAspace Extensions are different. The ShareAspace OOTB extension components are built using this pattern. Building custom Extensions using this pattern also imposes a strong contract for the communication between ShareAspace and the External Extension.
A custom External Extension must be protected using a symmetric key. They must also implement a predefined route for something called a metadata exchange (more on this further down).
When ShareAspace is calling these Extensions there are also a set of predefined envelope schemas for the body of the requests made to the Extensions. i.e. there is an envelope common for all ShareAspace requests, a content based on the type of extension, and a content payload that can be configured. This is described in more detail further down below.
Register
Using the ShareAspace Admin REST API, a Collection Administrator can register the Endpoint.
Tip
The Collection Administrator UI can also be used to register these. See the User Guide.
POST http://{FQDN}/api/admin/novaExtension
Content-Type: application/json
Body:
{
"hostUri": "https://xyz.eurostep.com/filePreview",
"apiKey": "RNXux1J6PUOYcgxbVUPp/xiC0oQxMG+bBSv01jC//4VmkYA9/9BfcFbNEXT+D/zVuV5Zu1jn7fqM3VqqQiu9og==",
"tokenLifeTime": 15,
"active": true
}
Properties:
Name | Required | Type | Details |
---|---|---|---|
hostUri |
Yes | string |
The base URL to the to the external endpoint. This URL together with a path, described by the extension, is used by ShareAspace when calling the endpoint. |
apiKey |
Yes | string |
A symmetric key used for protecting the ShareAspace extension. ShareAspace will use this key to sign requests to the Extension and the Extension will validate the request against this key. |
tokenLifeTime |
Yes | int |
The time, in minutes, that the JWT access token will be valid for. This token cannot be refreshed. |
active |
bool |
To activate/deactivate the Extension. If no value is provided, it will default to true . It is possible to enable/disable an endpoint at runtime. |
Metadata Exchange
Once a ShareAspace Trusted Extension is registered or when an existing extension is updated the Metadata Exchange takes place. During the manifest exchange, ShareAspace will fetch metadata about the External Endpoint from the Endpoint Host.
Note
The Metadata Exchange will only take place when an External Extension is added or updated.
ShareAspace will always combine the configured hostUri
for the External Extension with the route nova/extension
when
asking for the metadata. i.e. you need to have this route configured on your custom service.
e.g. My custom External Extension API has the hostUri
https://myServer/myAPI
. ShareAspace will therefore do a HTTP
GET request against https://myServer/myAPI/nova/extension
.
The response must be an array of JSON objects fulfilling the JSON Schema:
{
"$schema": "http://json-schema.org/draft-04/schema#",
"type": "object",
"required": [ "id", "version", "name", "endpoint", "extensionType", "category" ],
"additionalProperties": false,
"properties": {
"id": {
"type": "string"
},
"description": {
"type": "string"
},
"version": {
"type": "string"
},
"name": {
"type": "string"
},
"endpoint": {
"type": "string"
},
"extensionType": {
"type": "string",
"enum": [ "FilePreview", "Email", "ExternalValidation", "ExternalEvent", "ExternalTask", "FullTextIndexing", "FullTextSearch", "EventLogging", "ExternalAction", "ExternalView", "NameValue", "FilePreview", "FileConverter", "Identity" ]
},
"category": {
"type": "string"
},
"requestTimeout": {
"type": "number"
},
"retryForever": {
"type": "boolean"
},
"rateLimitNumberOfExecutions": {
"type": "number"
},
"capabilities": {
"type": "array",
"items": {
"type": "object",
"required": [ "capabilityType", "capabilities" ],
"additionalProperties": false,
"properties": {
"capabilityType": {
"type": "string",
"enum": [ "SoftType" ]
},
"capabilities": {
"type": "array",
"items": {
"type": "string"
}
}
}
}
},
"permissions": {
"type": "object",
"required": [ "tokenCallback", "permissions" ],
"additionalProperties": false,
"properties": {
"tokenCallback": {
"type": "string"
},
"permissions": {
"type": "array",
"items": {
"type": "string",
"enum": [ "TaskUploadAPI", "AuthorizationAPI", "AdministrationAPI", "SnapshotAPI", "LicenseCommunicationAPI" ]
}
}
}
}
}
}
Properties:
Name | Required | Type | Description | |
---|---|---|---|---|
id |
Yes | string |
The id of the extension. | |
description |
No | string |
A short description of what your extension is and does. | |
version |
Yes | string |
SemVer compatible version of the extension. | |
name |
Yes | string |
The name of the extension. | |
endpoint |
Yes | string |
Relative route to the extension base URI - this is used together with registered base address in ShareAspace. | |
extensionType |
Yes | string |
The type of extension e.g. FilePreview - unsupported extensions types will be ignored by ShareAspace. |
|
category |
Yes | string |
The category of the extension. The category is like a tag. The ShareAspace subscription UI will use this category to help the user configuring a subscription. | |
requestTimeout |
int |
Default 100 seconds. | The time that ShareAspace will wait for a response from the endpoint. | |
retryForever |
bool |
Default false. If set to true ShareAspace will keep retrying sending the message indefinitely if there is a transient HTTP error reported by the endpoint. | ||
rateLimitNumberOfExecutions |
int |
Default 5. The number of request executions ShareAspace should allow in the timespan of 1 minute before all request to the endpoint are paused for 1 minute. Incoming requests are queued and will be delivered when there is resources enough to continue. | ||
capabilities |
No | array |
Defines the capabilities of the extension (see specific note below). Not applicable to all types. | |
permissions |
No | object |
Holds the configuration for requested permissions of the extension. Activating the permissions makes it possible for the extension to retrieve ShareAspace API keys (non-user-impersonating keys). These keys are rotated every 24hrs . Once configured the extension can request the keys using the ShareAspace API. ShareAspace will respond with the keys using a POST request to the configured tokenCallback address. |
The capabilities array described above, is an array of objects, with the following properties:
Name | Required | Type | Details |
---|---|---|---|
capabilityType |
Yes | string |
The capability type of the capability, e.g. SoftType (for Validation) or MimeType (for supported File Preview types and supported files that an External Task can manage). |
capabilities |
Yes | array |
An array of capabilities, e.g. the SoftType ids that an external validation supports, ["Part", "Document"]. |
For the Extension Type ExternalValidation
the following capability types are supported.
Capability Type | Description |
---|---|
SoftType |
Used for evaluating either a level state in a Maturity System or validating if a SharePackage can be Shared. The capabilities list will list the ids of SoftTypes where the validation is applicable. For Sharing validation the capability list would contain SoftType ids for configured SharePackages, e.g. SharePack . |
The capabilities can be defined to anything in a custom scenario. For the InReach Extensions there is a set of predefined capabilities.
Permissions:
API Key | Description |
---|---|
TaskUploadAPI |
Used for installing internal DataExchange tasks. |
AuthorizationAPI |
Used for managing ShareAspace internal user accounts. |
AdministrationAPI |
Used for managing a ShareAspace collection as a non authorized collection administrator. |
SnapshotAPI |
Used for creating and restoring ShareAspace snapshots. |
LicenseCommunicationAPI |
Used for managing the ShareAspace license. |
Example of a Metadata exchange request and response:
GET: https://xyz.eurostep.com/InReachExtensions/nova/extension
Content-Type: application/json
Authorization: Bearer eyJ0eXA...
Note
That there is an Authorization header in these requests. The value is a signed
representation of the path /nova/extension
. The path is signed using the
defined symmetric API key for the extension.
Sample code, simulating the ShareAspace metadata request:
function GetAuthorizationHeader ($key, $path){
$encodedPath = [Text.Encoding]::ASCII.GetBytes($path)
$sha = New-Object System.Security.Cryptography.HMACSHA512
$sha.key = [Convert]::FromBase64String($key)
$hash = $sha.ComputeHash($encodedPath)
$hashString = [Convert]::ToBase64String($hash)
$bearerToken = $hashString.Split('=')[0]
$bearerToken = $bearerToken.Replace('+', '-')
$bearerToken = $bearerToken.Replace('/', '_')
return @{"Authorization" = ("Bearer", $bearerToken -join " ")}
}
$apiKey = "Gv26qA7ZM3aCdOD...78ZHEkk+2aNkI5BQ=="
$path = "/nova/extension"
$uri = "https://xyz.eurostep.com/InReachExtensions" + $path
$headers = GetAuthorizationHeader $apiKey $path
$response = Invoke-RestMethod -Method Get -Uri $uri -ContentType "application/json" -Headers $headers
Response:
[
{
"id": "ValidatePromoteToEndState",
"description": "This is perform external validation on a Maturity System state.",
"version": "1.0.0",
"name": "ValidatePromoteToEndState",
"endpoint": "nova/extension/ValidatePromoteToEndState",
"extensionType": "ExternalValidation",
"category": "Custom",
"capabilities": [
{
"capabilityType": "SoftType",
"capabilities": [
"Part",
"Document"
]
}
]
},
{
"id": "ValidateShareShareableDefinition",
"description": "This is perform external validation on SharePack for the shareable definition.",
"version": "1.0.0",
"name": "ValidateShareShareableDefinition",
"endpoint": "nova/extension/ValidateShareShareableDefinition",
"extensionType": "ExternalValidation",
"category": "Custom",
"capabilities": [
{
"capabilityType": "SoftType",
"capabilities": [
"SharePack"
]
}
]
},
{
"id": "ValidateShareShareableDefinitionForced",
"description": "This is perform external validation on SharePack for the shareable definition in forced mode.",
"version": "1.0.0",
"name": "ValidateShareShareableDefinitionForced",
"endpoint": "nova/extension/ValidateShareShareableDefinitionForced",
"extensionType": "ExternalValidation",
"category": "Custom",
"capabilities": [
{
"capabilityType": "SoftType",
"capabilities": [
"SharePack"
]
}
]
},
{
"id": "OnPromoteToEndState",
"description": "This extension is to handle external events for InReachExtensions when promoting to end state in a maturity system.",
"version": "1.0.0",
"name": "OnPromoteToEndState",
"endpoint": "nova/extension/OnPromoteToEndState",
"extensionType": "ExternalEvent",
"category": "Event"
},
{
"id": "OnShareShareableDefinition",
"description": "This extension is to handle external events for InReachExtensions when promoting to end state in a maturity system.",
"version": "1.0.0",
"name": "OnShareShareableDefinition",
"endpoint": "nova/extension/OnShareShareableDefinition",
"extensionType": "ExternalEvent",
"category": "Event"
},
{
"id": "AToBMapperTask",
"description": "This is an external DataExchange Task for mapping data from format A to B.",
"version": "1.0.0",
"name": "AToBMapperTask",
"endpoint": "nova/extension/A2BMap",
"extensionType": "ExternalTask",
"category": "DataExchange",
"capabilities": [
{
"capabilityType": "MimeType",
"capabilities": [
"application/format-A-type"
]
}
]
},
{
"id": "ExternalActionTestOk",
"description": "Test external action ok result.",
"version": "1.0.0",
"name": "External action ok",
"endpoint": "nova/extension/external-action-ok",
"extensionType": "ExternalAction",
"category": "Custom",
"capabilities": [
{
"capabilityType": "SoftType",
"capabilities": [
"SharePack",
"Part",
"Document"
]
}
]
},
{
"id": "ExternalActionTestNotOk",
"description": "Test external action not ok result.",
"version": "1.0.0",
"name": "External action ok",
"endpoint": "nova/extension/external-action-not-ok",
"extensionType": "ExternalAction",
"category": "Custom",
"capabilities": [
{
"capabilityType": "BaseType",
"capabilities": [
"Part"
]
}
]
}
]
Requesting API key
POST https://{FQDN}/api/collection/externalExtension/acquireAccessToken/{extensionId}
Content-Type: application/json
{
"tokenCallback": "https://{FQDN}/callback",
"permissions": [
"TaskUploadAPI",
"AdministrationAPI
]
}
Response at callback:
POST {tokenCallback}
Content-Type: application/json
{
"AuthorizationAPI": {
"apiKey": "{apiKey}"
},
"TaskUploadAPI": {
"apiKey": "{apiKey}"
}
}
Note
That the tokenCallback
must match what is configured in the metadata file of the ShareAspace extension. Only the permissions defined in the metadata can be requested.
External Event
ShareAspace will call Endpoints for External Events using an HTTP POST. With a predefined contract for the request body.
POST: https://xyz.eurostep.com/InReachExtensions/nova/extension/OnPromoteToEndState
Content-Type: application/json
Authorization: Bearer eyJ0eXA...
Note
The Authorization header is a signed representation of the path /nova/extension/OnPromoteToEndState
.
The path is signed using the defined symmetric API key for the extension.
{
"id": "534A128F-AFA8-4F33-ABBB-693971F34ECC",
"accessToken": "ey123...",
"baseAddress": "https://xyz.eurostep.com/",
"informationFilter": "ryDKJ23...s903",
"payload": {
"contentPayload": {
...
},
"id": "OnPromoteToEndState",
"spaceId": "inreach"
}
}
Property | Type | Description |
---|---|---|
id |
string |
A generated GUID, unique for the request. This id is used as the X-correlation-id when reporting logging information back to ShareAspace. If the request that led to the event triggering provided a X-correlation-id request header, the id will match this value. |
accessToken |
string |
A JWT access token issued with a life span according to the configuration. The access token is for impersonating a user that either triggered the event or the owner of the subscription. |
baseAddress |
string |
The address configured as the base address during the bootstrap. Typically the ShareAspace reverse proxy. This allows for the External Extension to serve multiple ShareAspace installations, since this address can be used by the extension to use the REST APIs of the server that created the request. |
informationFilter |
object |
Base64 string of the information filter settings object. |
payload |
object |
The payload unique for External Event. |
contentPayload |
object |
The payload that has been configured on the event handler. This could be any JSON data. Only JSON, i.e. Content-Type: application/json is supported. |
id |
string |
The id of the External Event resource. |
spaceId |
string |
The space id of the space from which the request to the extension service is made. |
Default values transient HTTP error
- Timeout 100 seconds
- 5 retries on transient HTTP error [ 2 sec, 4 sec, 8 sec, 16 sec, 32 sec ]
External Validation
ShareAspace will call Endpoints for External Validation using an HTTP POST. With a predefined contract for the request body.
POST: https://xyz.eurostep.com/InReachExtensions/nova/extension/ValidatePromoteToEndState
Content-Type: application/json
Authorization: Bearer eyJ0eXA...
Note
That the impersonation JWT
access token has been appended as a query parameter. The Authorization
header is a signed representation of the path /nova/extension/ValidatePromoteToEndState
.
The path is signed using the defined symmetric API key for the extension.
{
"id": "216305EA-A02C-4DAD-B2D8-B82BEE9F651C",
"accessToken": "ey123...",
"baseAddress": "https://xyz.eurostep.com/",
"informationFilter": "ryDKJ23...s903",
"payload": {
"objectId": "0023200124...",
"contextObjectId": "111....",
"spaceId": "inreach"
}
}
Property | Type | Description |
---|---|---|
id |
string |
A generated GUID, unique for the request. This id is used as the X-correlation-id when reporting logging information back to ShareAspace. If the request that led to the event triggering provided a X-correlation-id request header, the id will match this value. |
accessToken |
string |
A JWT access token issued with a life span according to the configuration. The access token is for impersonating a user that either triggered the event or the owner of the subscription. |
baseAddress |
string |
The address configured as the base address during the bootstrap. Typically the ShareAspace reverse proxy. This allows for the External Extension to serve multiple ShareAspace installations, since this address can be used by the extension to use the REST APIs of the server that created the request. |
informationFilter |
object |
Base64 string of the information filter settings object. |
payload |
object |
The payload unique for External Validation. |
objectId |
string |
The ObjectId of the object that should be validated. |
contextObjectId |
string |
(Only when used in the context object module) The ObjectId for the Context object. |
spaceId |
string |
The space id of the space from which the request to the extension service is made. |
Important
A response from the External Extension in the form of a JSON object is required when running an External Validation.
Validation Response Example
{
"isValid": true,
"message": "Validation Succesful!"
}
Default values transient HTTP error
- Timeout 100 seconds
- 3 retries on transient HTTP error [ 2 sec, 4 sec, 8 sec ]
- Less number of retries because external validation is called directly by an end user. It is only possible to change the timeout.
External Task
ShareAspace will call External Tasks, starting a long running external process, using an HTTP POST. With a predefined contract for the request body.
POST: https://xyz.eurostep.com/InReachExtensions/nova/extension/A2BMap
Content-Type: application/json
Authorization: Bearer eyJ0eXA...
Note
That the impersonation JWT
access token has been appended as a query parameter. The Authorization
header is a signed representation of the path /nova/extension/A2BMap
.
The path is signed using the defined symmetric API key for the extension.
{
"id": "0200000000000000240001000000",
"accessToken": "eyJ0eXAiOiJKV1QiLCJhbG...L9ErI-1YeVqcludL9SwAAQ",
"baseAddress": "https://xyz.eurostep.com/api",
"informationFilter": "ryDKJ23...s903",
"payload": {
"timeout": 600,
"jobSettings": {
"timeZone": "Europe/London",
"language": "en",
"culture": "en-us",
"effectivityMode": "Live"
},
"taskSettings": {...},
"links": [
{
"id": "inputDir",
"method": "GET",
"url": "https://xyz.eurostep.com/api/space/testmm/user/fs/dir"
},
{
"id": "inputFile",
"method": "GET",
"url": "https://xyz.eurostep.com/api/space/testmm/user/fs/file/SampleDataNew.xlsx?token={token}"
},
{
"id": "taskStatus",
"method": "PUT",
"url": "https://xyz.eurostep.com/api/space/testmm//dx/0200000000000000240001000000/status/{status}"
},
{
"id": "taskProgress",
"method": "PUT",
"url": "https://xyz.eurostep.com/api/space/testmm//dx/0200000000000000240001000000/progress"
},
{
"id": "uploadFileStream",
"method": "POST",
"url": "https://xyz.eurostep.com/api/space/testmm/user/fs/file/stream/{id}"
},
{
"id": "uploadFile",
"method": "POST",
"url": "https://xyz.eurostep.com/api/space/testmm/user/fs/file"
},
{
"id": "content",
"method": "GET",
"url": "https://xyz.eurostep.com/api/space/testmm/{*path}"
},
{
"id": "downloadFile",
"method": "GET",
"url": "https://xyz.eurostep.com/api/space/testmm/{container}/fs/dir/{*path}?token={token}"
}
]
}
}
Property | Type | Description |
---|---|---|
id |
string |
A generated GUID, unique for the request. This id is used as the X-correlation-id when reporting logging information back to ShareAspace. If the request that led to the event triggering provided a X-correlation-id request header, the id will match this value. |
accessToken |
string |
A JWT access token issued with a life span according to the configuration. The access token is for impersonating the user that scheduled the DataExchange Job. |
baseAddress |
string |
The address configured as the base address during the bootstrap. Typically the ShareAspace reverse proxy. This allows for the External Extension to serve multiple ShareAspace installations, since this address can be used by the extension to use the REST APIs of the server that created the request. |
informationFilter |
object |
Base64 string of the information filter settings object. |
payload |
object |
The payload unique for External Task. |
timeout |
number |
The time out time, in seconds, before the ShareAspace DataExchange job times out the external task and fails the job. This value can be configured for the External DX Task by setting the timeout property in the SoftType configuration for it (optional). If omitted, the default value is set to 600 seconds. |
jobSettings |
string |
All the settings that has been configured for the DX Job that requested a job from the External Task. |
taskSettings |
string |
All the settings that has ben configured for the External DX Task. |
Links
Id | Method | Description |
---|---|---|
inputDir |
GET | The path to the unmanaged file directory where the DataExchange Job input/output file is located. |
inputFile |
GET | The path to the DataExchange Job input/output file is (unmanaged file vault). |
taskStatus |
PUT | Used for updating the External Task status. |
taskProgress |
PUT | Used to report status from the External Task back to the DataExchange Job. |
uploadFileStream |
POST | URL for stream file upload. Default upload location is the same path as the task input file. |
uploadFile |
POST | URL for chunked file upload. Default upload location is the same path as the task input file. |
content |
GET | Template URL for uploading files. |
downloadFile |
GET | Template URL for downloading files. |
Important
The external endpoint should respond immediately after receiving the message. The External Service running the External Task is responsible for making sure that the Task is executing in the background. The external service is responsible for downloading the input to the task, uploading the result from the task, as well as reporting the progress and the result of the job (as in Completed, Canceled, Failed).
Task Status
PUT https://xyz.eurostep.com/api/space/{spaceId}/dx/{DX-job-oid}/status/{status}
Content-Type: application/json
Completed
This status should be set when the External Task considers it self to be completed. If the External Task has uploaded a resulting file that should be further used by the DataExchange Job and/or the External Task has provided a log file to the DataExchange Job. The Completed message should tell the job where to find these files (i.e. where in the unmanaged file area where the External Task uploaded these files).
Example:
PUT https://xyz.eurostep.com/api/space/space1/dx/0600000000000000240001000000/status/Completed
Content-Type: application/json
{
"outputFilePath": "participant:///OEM/folder/out_file.json",
"logFilePath": "participant:///OEM/folder/log_file.log"
}
Canceled
The Canceled status can be used if the External Service for some reason is canceled. If the External Task is reported as canceled, the DataExchange Job will be reported as failed. It is possible to provide a path to a log file in the cancel message.
Failed
If the External Task fails, the Failed status should be reported. It is possible to provide a path to a log file in the failed message.
Task Progress
Since the External Task typically would execute as a long running process it is possible to report the status of the External Task back to the DataExchange Job. Doing this is a good practice since the progress will be visible on the DataExchange Job. i.e. it gives users and or systems an idea of where in the process the External Task currently is.
Example:
PUT https://xyz.eurostep.com/api/space/space1/dx/0600000000000000240001000000/progress
Content-Type: application/json
{
"message": "Uploading log files. Task completion status 80%"
}
ShareAspace will call Email Endpoints an HTTP POST. With a predefined contract for the request body.
POST: https://xyz.eurostep.com/InReachExtensions/nova/extension/SMTPMail
Content-Type: application/json
Authorization: Bearer eyJ0eXA...
Note
That the impersonation JWT
access token has been appended as a query parameter. The Authorization
header is a signed representation of the path /nova/extension/SMTPMail
.
The path is signed using the defined symmetric API key for the extension.
{
"id": "216305EA-A02C-4DAD-B2D8-B82BEE9F651C",
"accessToken": "ey123...",
"baseAddress": "https://xyz.eurostep.com/",
"informationFilter": "ryDKJ23...s903",
"payload": {
"to": "john.doe@eurostep.com",
"from": "adin@eurostep.com",
"subject": "This is an email",
"body": ""
}
}
Property | Type | Description |
---|---|---|
id |
string |
A generated GUID, unique for the request. This id is used as the X-correlation-id when reporting logging information back to ShareAspace. If the request that led to the event triggering provided a X-correlation-id request header, the id will match this value. |
accessToken |
string |
A JWT access token issued with a life span according to the configuration. The access token is for impersonating a user that either triggered the event or the owner of the subscription. |
baseAddress |
string |
The address configured as the base address during the bootstrap. Typically the ShareAspace reverse proxy. This allows for the External Extension to serve multiple ShareAspace installations, since this address can be used by the extension to use the REST APIs of the server that created the request. |
informationFilter |
object |
Base64 string of the information filter settings object. |
payload |
object |
The payload unique for External Validation. |
to |
string |
The email address to whom the email should be sent. |
from |
string |
The email address that will show from the email was sent. |
subject |
string |
The subject of the email sent. |
body |
string |
The actual email message. Could be a string but could also be formatted using a format like HTML. |
Default values transient HTTP error
- Timeout 600 seconds
- 5 retries on transient HTTP error [ 2 sec, 4 sec, 8 sec, 16 sec, 32 sec ]
External Action
ShareAspace will call Endpoints for External Actions using an HTTP POST. With a predefined contract for the request body.
POST: https://xyz.eurostep.com/InReachExtensions/nova/extension/ExternalActionTestOk
Content-Type: application/json
Authorization: Bearer eyJ0eXA...
Note
The Authorization header is a signed representation of the path /nova/extension/ExternalActionTestOk
.
The path is signed using the defined symmetric API key for the extension.
{
"id": "051e6d7997ef48dba4b6830fb3b179e2",
"accessToken": "eyJh...Qs_XpA",
"baseAddress": "https://esaz906.eurostep.com/api",
"informationFilter": "ryDKJ23...s903",
"payload": {
"objectId": "0200000000000000120105000000",
"spaceId": "test",
"requestedRoute": "https://my.machine.net/api/space/test/softtype/Part/defaultIn/0100000000000000120105000000",
"httpVerb": "PATCH",
"informationFilter": "ryDKJ23...s903",
"sasUOIVersion": 1,
"contentPayload": ...,
"email": "oem.pa@eurostep.com"
}
}
Property | Type | Description |
---|---|---|
id |
string |
A generated GUID, unique for the request. This id is used as the X-correlation-id when reporting logging information back to ShareAspace. If the request that led to the event triggering provided a X-correlation-id request header, the id will match this value. |
accessToken |
string |
A JWT access token issued with a life span according to the configuration. The access token is for impersonating a user that either triggered the event or the owner of the subscription. |
baseAddress |
string |
The address configured as the base address during the bootstrap. Typically the ShareAspace reverse proxy. This allows for the External Extension to serve multiple ShareAspace installations, since this address can be used by the extension to use the REST APIs of the server that created the request. |
payload |
object |
The payload unique for External Action. |
informationFilter |
object |
Base64 string of the information filter settings object. |
objectId |
string |
The database id of the object that was selected for the action (if applicable). |
spaceId |
string |
The space id of the space from which the request to the extension service is made. |
requestedRoute |
string |
Only applicable to form actions. the request route that ShareAspace had intended to use by default if the action was not configured. |
httpVerb |
string |
Only applicable to form actions. The HTTP verb of the request that ShareAspace had intended to use by default if the action was not configured. |
informationFilter |
string |
Base64 encoded string of the information filter settings used by the user triggering the actions. |
sasUOIVersion |
string |
The current sasUOIVersion of the object that was selected for the action (if applicable). |
contentPayload |
object/array |
For form actions, this is the payload that ShareAspace normally would have sent to the requestedRoute if there was no action configured. Note that actions are also supported for batch requests. If the form is using a custom extension form, the payload will be the return payload from that form. For ribbon actions there is a separate schema, see below. This could be any JSON data. Only JSON, i.e. Content-Type: application/json is supported. |
email |
string |
The email address of the user triggering the request. |
Content payload for ribbon menu action
For all modules except the "Object context module" the content payload contains the database id of the object selected.
"contentPayload": {
"selectedObject": {
"$oid": "0100000000000000120105000000"
}
}
For the "Object context module" the content payload contains the database id of the context object, and if there is a selection within the module, the database id of that selected object.
"contentPayload": {
"selectedObject": { // included if there is a selection
"$oid": "0100000000000000120105000000"
},
"contextObject": {
"$oid": "0200000000000000120105000000"
}
}
Responses
- Response code
200
tells ShareAspace Web that the operation was successful and the form is closed (if form). - Response code
500
requires a correctly formatted error message. Error messages will show up as warning in SAsWeb.
Error message contract:
{
"errors": [
{
"message": "Some error"
},
{
"message": "Some other error"
}
]
}
Successful response contract:
{
"statusCode": 200, // should use the code applicable to the httpVerb in the request.
"location": "https://my.machine.net/api/space/test/softtype/Part/0f00000000000000120105000000",
"sasUOIVersion": 1
}
For Batch requests these responses are returned as an array,
[
{
"statusCode": 200, // should use the code applicable to the httpVerb in the request.
"location": "https://my.machine.net/api/space/test/softtype/Part/0f00000000000000120105000000",
"sasUOIVersion": 1
},
...
]
Property | Type | Description |
---|---|---|
statusCode |
number |
The response code from the request to the requestedRoute specified in the External Action message. |
location |
string |
The location header value from the response headers in the response from requestedRoute as specified in the External Action message. |
sasUOIVersion |
number |
The sasUOIVersion header value from the response headers in the response from requestedRoute as specified in the External Action message. |
Default values transient HTTP error
- Timeout 100 seconds
- 3 retries on transient HTTP error [ 2 sec, 4 sec, 8 sec ]
- Less number of retries because external validation is called directly by an end user. It is only possible to change the timeout.
External name/value list
ShareAspace will call Endpoints for External name/value lists using an HTTP POST. Using a predefined contract for the request body.
POST: https://xyz.eurostep.com/InReachExtensions/nova/extension/NameValueExtensionTestOk
Content-Type: application/json
Authorization: Bearer eyJ0eXA...
Note
The Authorization header is a signed representation of the path /nova/extension/NameValueExtensionTestOk
.
The path is signed using the defined symmetric API key for the extension.
{
"id": "051e6d7997ef48dba4b6830fb3b179e2",
"accessToken": "eyJh...Qs_XpA",
"baseAddress": "https://esaz906.eurostep.com/api",
"informationFilter": "ryDKJ23...s903"
}
Property | Type | Description |
---|---|---|
id |
string |
A generated GUID, unique for the request. This id is used as the X-correlation-id when reporting logging information back to ShareAspace. If the request that led to the event triggering provided a X-correlation-id request header, the id will match this value. |
accessToken |
string |
A JWT access token issued with a life span according to the configuration. The access token is for impersonating a user that either triggered the event or the owner of the subscription. |
baseAddress |
string |
The address configured as the base address during the bootstrap. Typically the ShareAspace reverse proxy. This allows for the External Extension to serve multiple ShareAspace installations, since this address can be used by the extension to use the REST APIs of the server that created the request. |
informationFilter |
object |
Base64 string of the information filter settings object. |
Responses
- Response code
200
tells ShareAspace Web that the operation was successful and the form is closed (if form). - Response code
500
requires a correctly formatted error message. Error messages will show up as warning in SAsWeb.
Error message contract:
{
"errors": [
{
"message": "Some error"
},
{
"message": "Some other error"
}
]
}
Successful response contract:
{
"data": [
{
"name": "Name one",
"value": "name1"
},
{
"name": "Name two",
"value": "name2"
}
]
}
Default values transient HTTP error
- Timeout 100 seconds
- 3 retries on transient HTTP error [ 2 sec, 4 sec, 8 sec ]
- Less number of retries because external validation is called directly by an end user. It is only possible to change the timeout.
External Validation Scenario
To exemplify a full flow for a set of External Validations for Maturity States of a SoftType identified as
Part
.
We have a custom External Extension API with a hostUri
https://myServer/myAPI
. When registering the
ShareAspace Extension, ShareAspace will request the Metadata Exchange using an HTTP GET request against
https://myServer/myAPI/nova/extension
.
Response:
[
{
"id": "ValidateInWork",
"description": "This is perform external validation on a Maturity System state.",
"version": "1.0.0",
"name": "ValidateInWork",
"endpoint": "nova/extension/ValidateInWork",
"extensionType": "ExternalValidation",
"category": "Custom",
"capabilities": [
{
"capabilityType": "SoftType",
"capabilities": [
"Part"
]
}
]
},
{
"id": "ValidateReleased",
"description": "This is perform external validation on a Maturity System state.",
"version": "1.0.0",
"name": "ValidateReleased",
"endpoint": "nova/extension/ValidateReleased",
"extensionType": "ExternalValidation",
"category": "Custom",
"capabilities": [
{
"capabilityType": "SoftType",
"capabilities": [
"Part"
]
}
]
},
{
"id": "ValidateDeprecated",
"description": "This is perform external validation on a Maturity System state.",
"version": "1.0.0",
"name": "ValidateDeprecated",
"endpoint": "nova/extension/ValidateDeprecated",
"extensionType": "ExternalValidation",
"category": "Custom",
"capabilities": [
{
"capabilityType": "SoftType",
"capabilities": [
"Part"
]
}
]
}
]
We can see from this made up example that the custom External Extension has been setup to do External Validations for Maturity Systems.
There are three validations defined: ValidateInWork
, ValidateReleased
, and ValidateDeprecated
. I.e. my custom External Extension
can do three types of Maturity System validation. Ids of these endpoints can be used when configuring a Maturity System.
Important
Up to version 1.5 of ShareAspace when configuring External Validations the request URI was specified in the configuration directly. From version 1.6 this has been replaced with using these capability ids instead. This goes for Maturity System configurations, SharePack validation configurations, and when defining "endpoints" for External Events WebHooks that require impersonation.
Continuing with the example, say that the Part SoftType is configured with a Maturity System. A State in this Maturity System is called "Released". The Maturity System configuration for this state says that the External Validation should be using the "ValidateReleased" extension endpoint.
When the user john.doe@eurostep.com tries to enter the state "Released" using the ShareAspace UI or the ShareAspace REST APIs. ShareAspace will send an external validation request.
POST: https://myServer/myAPI/nova/extension/ValidateReleased
We can see that the POST will be made to a combined Uri of the configured hostUri
and the endPoint
of the configured
External Extension.
In this case the payload would be something like:
{
"id": "216305EA-A02C-4DAD-B2D8-B82BEE9F651C",
"accessToken": "ey123...",
"baseAddress": "https://xyz.eurostep.com/",
"payload": {
"objectId": "0023200124...",
"spaceId": "inreach"
}
}
The access_token
would in this case be an impersonation token for john.doe@eurostep.com. I.e. during this validation
the External Service would be able to see the same data as John Doe. Any creates or updates on data in ShareAspace
would have the logs and metadata as if John Doe would have performed these operations himself.
External Task Scenario
A typical scenario for when to use the External DataExchange Tasks can be when there is a need to import data where the source format is something that ShareAspace does not have an OOTB mapper task to handle.
The External Task would then serve as a mapper service that could run a custom implemented mapper (preferable implemented using the ShareAspace mapping framework). This mapper would map the source format into something interpretable by either a ShareAspace OOTB mapper or the SoftType or UoI Importer.
The interaction flow between ShareAspace (the DataExchange engine) and the external task could look like:
Step | Description |
---|---|
0. | A DataExchange Job, configured with one External Task and the ShareAspace importer has started processing. |
1. | The External Task configuration has an identifier for an External Task, ShareAspace will check the registered ShareAspace Nova Extensions. If a Nova Extension has provided an ExternalTask with a matching identifier (matching with the External Task configuration) during the Metadata Exchange, ShareAspace will use the configured route to POST a message to the external service. Instructing it to start processing. |
2. | Once the external service receives the request, it should immediately respond back to ShareAspace with the 200 status code (provided everything in the message is correct). The mapper, that typically is a long running process should be scheduled as a background job. |
3. | The background job will start by downloading the input file that should be mapped. |
4. | The background job can keep the DataExchange Job updated with what is happening within the long running process. This information can be read by users and other systems once reported to the DataExchange Job. |
5. | Once the mapping is complete, the External Task uploads the output file from the mapper to the unmanaged file vault of ShareAspace. It can also provide a log file to the unmanaged file vault. |
6. | Once the files are uploaded to ShareAspace, the process reports back to the DataExchange Job that the Task was completed, providing links to the output file and log file. |
End. | The DataExchange Job picks up the output file provided by the External Task and passes it on to the next configured Task in the DataExchange Job. |