## Action Service
## Table of Contents
- [Introduction](#introduction)
- [Action APIs](#action-apis)
* [Registering an Action](#register-action)
* [Get an Action by ID](#get-action)
* [Retrieve Actions](#retrieve-action)
* [Delete an Action by ID](#delete-action)
* [Validate action](#regex-test)
* [Version info endpoint](#version-info-endpoint)
- [Current Limitations](#limitation)
## Introduction
The high level design of this service can conceptually be thought of similar to the 'command' design pattern. Essentially this pattern decouples a trigger from an action. This is often used in UIs where a trigger is perhaps a user clicking a button and the action is a program function that is triggered by the click. There is often an optional context which can provide the action with data to use in the function, as well as to enable / disable the action for the user (perhaps if the data is not relevant to the action in question).
This service will allow an application to register an action (the function to be triggered). It will expect data (context) to come from OSDU to enable the action, and the application can register a filter (enable/disable) to say what data can be used with this action.
[Back to Table of Contents](#TOC)
## Action APIs
### Registering an Action
This API allows registering an action in the form of a GET HTTPS URL and a filter. The filter specifies what data the action can be applied to.
> It is recommended that Admins first use the [Validate action](#regex-test) API, to make sure the action is acceptable and the output of the action with a test payload is as expected.
```
POST /api/register/v1/action
```
curl
```
curl --request POST \
--url 'https://register-svc.osdu.com/api/register/v1/action' \
--header 'authorization: Bearer ' \
--header 'content-type: application/json' \
--header 'data-partition-id: common' \
--data '{
"id": "petrel-launch-project",
"name": "Petrel Project",
"description": "This action launches the Petrel projects landing page that holds the selected data.",
"url": "https://myapp.osdu.com/action/{id}/{data.project}",
"img": "https://mycdn.com/img.png",
"contactEmail": "abc@test.com",
"filter": {
"entityType": ["regularheightfield", "project"],
"source": ["petrel"],
"version": ["*"]
}
}'
```
The filter specifies what data the action can be applied to. Each property in the filter is either values representing an exact match for the data it can handle or a single wildcard '*' indicating that any data can match that property filter.
The URL given on the registration must be a fully qualified HTTPS GET request. The URL can support templates as shown above e.g. {data.project}, as well as regular expressions. These templates can be applied anywhere in the given URL (domain, path, query etc.) The template values can be any property that matches a Record's payload.
The filter specifies which Records your action can be used with. The retrieve API applies the template onto a given Record to create the fully qualified URL. For instance, the above URL could be applied to the following Record in Storage.
```
{
"id": "common:doc:123456789",
"kind": "common:petrel:regularheightfield:1.0.0",
...
"data": {
"project":"myPetrelProj"
}
...
}
```
Because the filter of the action matches the Record (petrel and regularheightfield match the 'kind' and the version is a wildcard so matches 1.0.0), the resulting action after the template is applied would then be
```
https://myapp.osdu.com/action/common:doc:123456789/myPetrelProj
```
[Back to Table of Contents](#TOC)
## Get an Action by ID
This API allows getting an action with a given Id.
```
GET /api/register/v1/action/{id}
```
curl
```
curl --request GET \
--url 'https://register-svc.osdu.com/api/register/v1/action/petrel-launch-project' \
--header 'authorization: Bearer ' \
--header 'content-type: application/json' \
--header 'data-partition-id: common'
```
[Back to Table of Contents](#TOC)
## Retrieve Actions
This API allows retrieving all actions that match a given filter.
```
POST /api/register/v1/action:retrieve
```
So imagine you have a Record retrieved from OSDU:
```
{
"id": "common:regularheightfield:123456",
"kind": "common:petrel:regularheightfield:1.0.0",
"acl": {
"viewers": ["data.default.viewers@common.osdu.com"],
"owners": ["data.default.owners@common.osdu.com"]
},
"legal": {
"legaltags": ["common-sample-legaltag"],
"otherRelevantDataCountries": ["FR","US","CA"]
},
"data": {
"msg": "Hello"
}
}
```
And make the following call to retrieve actions API:
curl
```
curl --request POST\
--url 'https://register-svc.osdu.com/api/register/v1/action:retrieve' \
--header 'authorization: Bearer ' \
--header 'content-type: application/json' \
--header 'data-partition-id: common'
--data '{
"id": "common:regularheightfield:123456",
"kind": "common:petrel:regularheightfield:1.0.0",
"acl": {
"viewers": ["data.default.viewers@common.osdu.com"],
"owners": ["data.default.owners@common.osdu.com"]
},
"legal": {
"legaltags": ["common-sample-legaltag"],
"otherRelevantDataCountries": ["FR","US","CA"]
},
"data": {
"msg": "Hello"
}
}'
```
This will then find all actions whose filter matches your Record. It will then attempt to substitute any template value and also will evaluate the regular expression from the Record into the action.
Given two matching actions that had a "url" field with these templates
```
"url": "https://myapp.osdu.com/action/{id}",
and
"url": "https://myapp.osdu.com/action?text={data.msg}",
```
Then the response returns all matching actions with the substituted parameters specified:
```
[
{
"id": "123-456-abc",
"name": "Petrel",
"description": "Opens the given objects project in Petrel PTS",
"img": "https://mycdn.com/myimg.png",
"contactEmail": "abc@test.com",
"url": "https://myapp.osdu.com/action/common:regularheightfield:123456"
},
{
"id": "923-456-abc",
"name": "myApp2",
"description": "Does something awesome",
"img": "https://mycdn.com/myimg2.png",
"contactEmail": "abc@test.com",
"url": "https://myapp.osdu.com/action?text=Hello"
}
]
```
[Back to Table of Contents](#TOC)
## Delete an Action by ID
This API allows deleting an action with a given id.
```
DELETE /api/register/v1/action/{id}
```
curl
```
curl --request DELETE \
--url 'https://register-svc.osdu.com/api/register/v1/action/petrel-launch-project' \
--header 'authorization: Bearer ' \
--header 'content-type: application/json' \
--header 'data-partition-id: common'
```
[Back to Table of Contents](#TOC)
## Validate action
This API is a helper API method that allows users to validate their action is working as expected, including template and regular expression usage, before they create an action in the system.
```
POST /api/register/v1/action:test
```
Let's consider the following payload for [Register an Action](#register-action) request example
curl
```
curl --request POST \
--url 'https://register-svc.osdu.com/api/register/v1/action' \
--header 'authorization: Bearer ' \
--header 'content-type: application/json' \
--header 'data-partition-id: common' \
--data '{
"id": "petrel-launch-project",
"name": "Petrel Project",
"description": "This action launches the Petrel projects landing page that holds the selected data.",
"url": "https://myapp.osdu.com/action/{data.uri:^(?:[^\/]*(?:\/(?:\/[^\/]*\/?)?)?([^?]+)(?:\??.+)?)$}",
"img": "https://mycdn.com/img.png",
"contactEmail": "abc@test.com",
"filter": {
"entityType": ["regularheightfield", "project"],
"source": ["petrel"],
"version": ["*"]
}
}'
```
The above action applies a regular expression of
```
^(?:[^\/]*(?:\/(?:\/[^\/]*\/?)?)?([^?]+)(?:\??.+)?)$
```
onto the data.uri properties value.
This regular expression attempts to extract the path segment out of a URI. But before we register this action, we want to be sure that the specified regular expression is correct and return the expected value from expected payload for a kind. This can be achieved by following API call:
curl
```
curl --request POST\
--url 'https://register-svc.osdu.com/api/register/v1/action:test' \
--header 'authorization: Bearer ' \
--header 'content-type: application/json' \
--header 'data-partition-id: common'
--data '{
"action": {
"id": "petrel-launch-project",
"name": "Petrel Project",
"description": "This action launches the Petrel projects landing page that holds the selected data.",
"url": "https://myapp.osdu.com/action/{data.uri:^(?:[^\\/]*(?:\\/(?:\\/[^\\/]*\\/?)?)?([^?]+)(?:\\??.+)?)$}",
"img": "https://mycdn.com/img.png",
"contactEmail": "abc@test.com",
"filter": {
"entityType": ["regularheightfield", "project"],
"source": ["petrel"],
"version": ["*"]
}
},
"testPayload": {
"id": "common:regularheightfield:123456",
"kind": "common:petrel:regularheightfield:1.0.0",
"data": {
"uri": "https://myproj.com/abc123"
}
}
}'
```
And in this case the Response would be:
```
{
"url": "https://myapp.osdu.com/action/abc123",
"errors": ""
}
```
In the above example, the regular expression was valid and we see the response append the path of the data.uri property into the action and there are no errors.
However an error is returned if:
- The filter did not match the testPayload
- The regular expression was invalid
- The regular expression failed to extract a value from the test payload.
There is also the possibility that the regular expression extracts a value, but not the one you expected. In this scenario, the API does not return an error, so you need to validate the returned url is formed as you expected after it is mapped into the test payload.
Here are some regular expression registration examples:
| Example regular expression Registration | Example Record | Example Output|
|:---------------------------|:---------------|:--------------|
|`https://myapp.osdu.com/action/{data.uri:^(?:[^\\/]*(?:\\/(?:\\/[^\\/]*\\/?)?)?([^?]+)(?:\\??.+)?)$}`|`"data": {"uri": "https://myproj.com/abc123"}`| `https://myapp.osdu.com/action/abc123`|
|`https://myapp.osdu.com/action?type={kind:^(?:[A-Za-z]+\\:)*([A-Za-z]+)\\:(?:.+)$`|`"kind": "common:petrel:regularheightfield:1.0.0"`| `https://myapp.osdu.com/action?type=regularheightfield`|
|`https://myapp.osdu.com/action/{kind:^(?:[A-Za-z]+\\:)*(.+)}`|`"data": {"kind": "common:petrel:regularheightfield:1.0.0"}`| `https://myapp.osdu.com/action/1.0.0`|
|`https://myapp.osdu.com/action/{id}?type={kind:^(?:[^:]*:){2}([^:]*)}`|`data": {"id": "test-id", kind": "common:petrel:regularheightfield:1.0.0"}`| `https://myapp.osdu.com/action/test-id?type=regularheightfield`|
The regular expression match per record field is capped at a maximum of 2 seconds for performance reasons. Please take a look at the error message for detailed response.
[Back to Table of Contents](#TOC)
## Version info endpoint
For deployment available public `/info` endpoint, which provides build and git related information.
#### Example response:
```json
{
"groupId": "org.opengroup.osdu",
"artifactId": "storage-gcp",
"version": "0.10.0-SNAPSHOT",
"buildTime": "2021-07-09T14:29:51.584Z",
"branch": "feature/GONRG-2681_Build_info",
"commitId": "7777",
"commitMessage": "Added copyright to version info properties file",
"connectedOuterServices": [
{
"name": "elasticSearch",
"version":"..."
},
{
"name": "postgresSql",
"version":"..."
},
{
"name": "redis",
"version":"..."
}
]
}
```
This endpoint takes information from files, generated by `spring-boot-maven-plugin`,
`git-commit-id-plugin` plugins. Need to specify paths for generated files to matching
properties:
- `version.info.buildPropertiesPath`
- `version.info.gitPropertiesPath`
[Back to table of contents](#TOC)
## Current Limitations
There are mainly 2 limitations currently:
- Users need to individually register for each data partition they want the action enabled from.
- We don't support a wildcard in the action URL for the partition id. Something like myaction.com/kind?dpid={data-partition-id} may be supported in the future so that the request can be data partition aware.
[Back to Table of Contents](#TOC)