Table of Contents
Last updated: 2024-06-26

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%"
}

Email

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:

Typical External Task Scenario

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.