Docs
  • Getting Started
  • Overview
    • Understanding
      • User-Interface
      • Shortcuts
    • Getting Started
      • Creating A New Application
      • Adding Basic Structure using Class Designer
      • Creating a link to the TIVITY File Class
      • Setting Rights
      • Creating Queries
      • Building The Layout
        • Creating an App Page
        • Creating an Object Page
        • Creating a List Item Layout
  • Building an Application
    • Application Setup
      • General
      • Documentation
      • License Management
      • Publishing the Application
      • Advanced Settings
        • Document-MailEditor
    • Data
      • Sources
      • Data Modelling
        • Class
        • Field
        • Action
        • Link
      • Query Data
        • Get Started with Query Designer
        • Common
        • Fields
        • Conditions
        • Default Values
        • Preview
      • Roles & Permissions
        • Rights Designer
      • Access Control Lists (ACL)
    • Views
      • Design UI
        • Page Types
        • Fields and Links
        • Layout Controls
          • Actions
          • Panels
          • Sections
          • Lists
          • Input
        • Layout Templates
      • Document Templates
        • Get started with Template Designer
        • Expressions in Templates
    • Execution
      • Functions
      • Workflows
        • Control Types
      • Trigger
      • Scripting
        • Accessing the Script Designer
        • Using the Script Designer
        • Commonly used Actions
        • Reference: Actions
          • Math
          • System
          • Date
          • Collection
          • LogicalOperators
          • Web
          • Structure
          • Constants
          • Converters
          • Commands
          • Text
          • PDF
          • Operators
          • PowerPoint
          • QR-/Barcode
          • Messaging
          • Cells
          • Xml
          • Admin
          • Integrations
    • Expressions
      • Expressions in Expressions
      • Expressions in Condition Values
  • Administration
    • Platform
    • Workspace
    • Security
    • Platform Setup
  • Extensibility and Integration
    • REST API
    • Source Adapter
      • Getting Started
      • Source Adapter Interface
      • RESTful Adapter Service
  • Adapter Portfolio
    • MongoDB Adapter
  • Platform Features
    • Enterprise Search
      • Integration into an App
      • General Settings
    • Templates
    • Tagging
      • Getting Started
      • Manage Tags
      • Settings
      • Usage
        • Tag filter
        • Tag panel
    • DMS Setup
Powered by GitBook
On this page
  • 1. Purpose of the document
  • 2. Visual Studio Solution for REST Service
  • 3. Plugin Service Project
  • 3.1 SourceController
  • Source / Connect
  • Source / Define
  • Source / Config
  • Source / config
  • Source / Capability
  • 3.2 ActionController
  • Action / Execute
  • 3.3 SchemaController
  • Schema / Get
  • 3.4 QueryController
  • Query / Execute
  • 3.5 ModelController
  • Model / Create
  • Model / Update
  • Model / Delete
  • 3.6 DocumentController
  • Document / Download
  • 3.7 FileUpload-StorageController
  • Storage / Upload

Was this helpful?

  1. Extensibility and Integration
  2. Source Adapter

RESTful Adapter Service

Documentation about an example of a RESTful api service that consumes a source adapter.

PreviousSource Adapter InterfaceNextAdapter Portfolio

Last updated 4 years ago

Was this helpful?

1. Purpose of the document

This documentation contains an overview of the Visual Studio solution and descriptions of all REST service calls. Additional to all calls an example request and response as json objects are explained and displayed.

2. Visual Studio Solution for REST Service

Content of the solution:

The VS solution consists of three projects and one configuration:

  • TivityPluginService: WebAPI project, the actual plugin REST service

  • Tivity.Plugnis.Dummy: a example adapter serves inside the WebAPI as fallback adapter

  • Tivity.Plugins.RestService.Test: UnitTests for the REST Service project

  • docker-compose: the docker configuration, it is possible to start the service

    in the container out of the service.

After you build the solution, the service starts and the homepage appears in the browser from the plugin service. The start page is an openAPI documentation like swagger.

3. Plugin Service Project

This is a project created as a VS WebAPI project based on .NET core 2.1 and serves as the API interface for an adapter instance. This project is intended as example code for a REST Service which the TIVITY platform can communicate with. Of course, this service can also be used productively and a specially developed adapter connect and wrap. This adapter should be available as a Microsoft .NET assembly.

NOTE It can also be used a special developed adapter (e.g. Java). This must be identical to the interface used in the example service.

The service basically consists of the API controllers and the wrapper class. The controllers are the interfaces to "outside" while the wrapper ensures the communication "inside", namely to the adapter. In addition, there are the usual Startup and program classes for the service, which are used for the entry point. Further configurations are stored in the Dockerfile and appsettings.json.

3.1 SourceController

The SourceController is a important API controller for the communication with the SourceAdapter. There, the SourceAdapter interfaces (ISourceAdapter, ISource) are implemented. These interfaces provide the configuration and adapter instantiation as API calls.

The interface for the adapter is defined like this:

    public interface ISourceAdapter
    {
        Task<SourceResult<AdapterDefinition>> Define(AdapterDefineRequest request);
        Task<SourceResult<ConfigurationStep>> Config(AdapterConfigLaunchRequest request);
        Task<SourceResult<ConfigurationStep>> Config(AdapterConfigHandleRequest request);
        Task<SourceResult<ISource>> Connect(AdapterConnectRequest request);
    }
    public interface ISource
    {
        Task<SourceResult<SourceCapabilityMap>> GetCapabilityMap(SourceCapabilityRequest request);
        TCapability GetCapability<TCapability>() where TCapability : ISourceCapability;
    }

The corresponding methods in the API Controller look very similar (simplified method body):

public async Task<ActionResult<SourceResult<AdapterDefinition>>> Define(AdapterDefineRequest request)
{
    SourceResult<AdapterDefinition> result = await AdapterWrapper.Instance.Define(request);
    return result;
}

public Task<SourceResult<ISource>> Connect(AdapterConnectRequest request)
{
    return AdapterWrapper.Instance.Connect(request).Result;
}

public async Task<ActionResult<SourceResult<ConfigurationStep<ParameterStep>>>> Config()
{
    SourceResult<ConfigurationStep> result = await AdapterWrapper.Instance.Config(new AdapterConfigLaunchRequest());
   return new SourceResult<ConfigurationStep>(result.Value as ConfigurationStep<ParameterStep>); 
}

public async Task<ActionResult<SourceResult<ConfigurationStep>>> Config([FromBody] AdapterConfigHandleRequest value)
{
    SourceResult<ConfigurationStep> result = await AdapterWrapper.Instance.Config(value);
    return new SourceResult<ConfigurationStep>(result.Value as ConfigurationStep<ParameterStep>); 
}
public async Task<ActionResult<SourceResult<SourceCapabilityMap>>> GetCapability()
{
    return await AdapterWrapper.Instance.GetCapabilityMap(new SourceCapabilityRequest());
}

Except for Connect, all methods are asynchronous. And it is noticeable that another ActionResult type is given as a template. This is a standard Microsoft return type ActionResult<T> for asp.net core. and was just added for comfortable response generation. This type is not necessary for your own service. Otherwise the methods correspond to those of the interface ISourceAdapter.

Source / Connect

POST https://adapterservice/api/source/connect

The connect method configured the adapter inside the service. The request consists a bulk of configurations in JSON format or what else.

Request Body

Name
Type
Description

json object

string

{ "configuration": "string" }

{
  "messages": []
}

Request example for a configuration of user and password:

{
  "configuration": "{\"User\":\"test\",\"Password\":\"sd2rwe\"}"
}

Source / Define

POST https://adapterservice/api/source/define

The define method returns the basic information of the adapter. Properties are name and description. Additionally a thumbnail can be added. The request for define method can also be empty.

Request Body

Name
Type
Description

json object

string

Empty request body.

{
  "value": {
    "name": {
      "de-DE": "Basis Adapter",
      "en-EN": "Basic Adapter"
    },
    "description": {
      "de-DE": "Adapter zum testen der Schnittstelle.",
      "en-EN": "Adapter for testing the interface."
    },
    "thumbnail": {}
  },
  "messages": []
}

Source / Config

GET https://adapterservice/api/source/config

Starts the configuration process. Returns a configuration step with initial parameters. The parameters represent a form input on the platform configuration.

Request Body

Name
Type
Description

json object

string

Empty request body.

{
  "value": {
    "key": "string",
    "step": {
      "parameters": [
        {
          "key": "string",
          "type": 0,
          "name": {
            "additionalProp1": "string",
            "additionalProp2": "string",
            "additionalProp3": "string"
          },
          "description": {
            "additionalProp1": "string",
            "additionalProp2": "string",
            "additionalProp3": "string"
          },
          "error": {
            "additionalProp1": "string",
            "additionalProp2": "string",
            "additionalProp3": "string"
          },
          "value": {},
          "values": [
            {
              "key": "string",
              "name": {
                "additionalProp1": "string",
                "additionalProp2": "string",
                "additionalProp3": "string"
              }
            }
          ],
          "required": true
        }
      ]
    }
  }
}

Source / config

POST https://adapterservice/api/source/config

Handle the configuration process. In the request object AdapterConfigHandleRequest a list of configuration parameters are send to the service. This parameters are the input values from a configuration form.

Request Body

Name
Type
Description

json object

string

{ "key": "string", "parameters": { "additionalProp1": {}, "additionalProp2": {}, "additionalProp3": {} } }

{
  "messages": []
}

In the adapter source you can now validate this parameter values. If the values are valid you returned a success step. Otherwise you send a configuration step back, similar the start conf method (further up). But at this time with error messages in failed parameter objects.

Source / Capability

GET https://adapterservide/api/source/capability

Get a list of capabilities which are supported by the source adapter (service).

Path Parameters

Name
Type
Description

json object

string

Empty request body.

{
  "value": {
    "capabilities": [
      0,
      6,
      5,
      3
    ]
  },
  "messages": []
}

3.2 ActionController

For the adapter call with the method Execute, an ActionController exist with the same method. This controller has only this one method as well.

public async Task<ActionResult<SourceResult<object>>> Execute([FromBody] ActionExecuteRequest value)
{
    return await AdapterWrapper.Instance.Execute(value);
}

There are three properties in the ActionExecuteRequest.

parameter name

type

description

ClassName

str

Name of the class where action executed (optional)

ActionName

str

Name of the action, it could be multiple actions in adapter

Parameters

Dictionary

List of object, comparable with method parameters (key=param-name, value=object)

Action / Execute

GET https://adapterservice/api/action/execute

Request Body

Name
Type
Description

json object

string

example: { "className": "myClass", "actionName": "myAction", "parameters": { "parameter1": "myValue", "parameter2": { 3, 5 }, "parameter3": { "text 1", "text2" } } }

{
    "value": {
        "object as serialized string",
    },
    "messages": []
}

In this example response the object is a translation object, in property "value" (JSON):

{
    "value": {
        "en-EN": "Result text. This is the request: 'XXy'.",
        "de-DE": "Ergebnis Text. Hier ist der Request: 'XXy'."
    },
    "messages": []
}

3.3 SchemaController

The SchemaController has only one Method "Get" (HTTP POST). This method returns a list of schema definitions.

public async Task<ActionResult<SourceResult<Schema>>> Get(SchemaGetRequest request)
{
    return await AdapterWrapper.Instance.Get(request);
}

Schema / Get

POST https://adapterservice/api/schema/get

Method for getting schema definition information.

Request Body

Name
Type
Description

json object

string

empty request body.

{
  "value": {
    "classes": [
      {
        "name": "DummyClass",
        "fields": [
          {
            "name": "FieldStr",
            "length": 20,
            "defaultValue": null,
            "isNullable": false,
            "nameIntern": "intern-FieldStr",
            "dataSourceOption": null,
            "isReadOnly": false,
            "dataType": 2
          },
          {
            "name": "FieldDate",
            "length": 20,
            "defaultValue": null,
            "isNullable": false,
            "nameIntern": "intern-FieldDate",
            "dataSourceOption": null,
            "isReadOnly": false,
            "dataType": 3
          },
          {
            "name": "FieldInt",
            "length": 20,
            "defaultValue": null,
            "isNullable": false,
            "nameIntern": "intern-FieldInt",
            "dataSourceOption": null,
            "isReadOnly": false,
            "dataType": 4
          },
          {
            "name": "Created",
            "length": 20,
            "defaultValue": null,
            "isNullable": false,
            "nameIntern": "intern-Created",
            "dataSourceOption": null,
            "isReadOnly": false,
            "dataType": 3
          }
        ]
      }
    ],
    "links": [
      {
        "name": "#lnk-002c",
        "primaryClassName": "ClVehicle",
        "primaryFieldName": "TestField-ClVehicle-8",
        "foreignClassName": "ClMotor",
        "foreignFieldName": "TestField-ClMotor-2"
      }
    ]
  },
  "messages": []
}

3.4 QueryController

The QueryController has only one method and passes the request through to the adapter.

public async Task<ActionResult<SourceResult<ModelList>>> Execute(QueryExecuteRequest request)
{
    return await AdapterWrapper.Instance.Execute(request);
}

Query / Execute

POST https://adapterservice/apiquery/execute

Request Body

Name
Type
Description

json object

string

serialized query object. See example below.

{
  "value": {
    "models": [
      {
        "additionalProp1": { "property value" },
        "additionalProp2": {},
        "additionalProp3": {}
      }
    ],
    "total": 1
  }
}

! Important: specify the expression type in json request.

{
    "Query": {
        "From": {
            "ClassName": "TestClass",
            "Alias": "c"
        },
        "Joins": null,
        "Columns": [
            {
                "Expression": {
                    "$type": "Tivity.Plugins.Models.ExpressionField, Tivity.Plugins",
                    "ClassAlias": null,
                    "FieldName": "Field1"
                },
                "Alias": null
            },
            {
                "Expression": {
                    "$type": "Tivity.Plugins.Models.ExpressionField, Tivity.Plugins",
                    "ClassAlias": null,
                    "FieldName": "Field3"
                },
                "Alias": null
            }
        ],
        "Conditions": [
            {
                "LeftParentheses": 1,
                "LeftExpression": {
                    "$type": "Tivity.Plugins.Models.ExpressionQuery, Tivity.Plugins",
                    "From": {
                        "ClassName": "TestClass",
                        "Alias": "c"
                    },
                    "Joins": null,
                    "Column": {
                        "Expression": {
                            "$type": "Tivity.Plugins.Models.ExpressionField, Tivity.Plugins",
                            "ClassAlias": null,
                            "FieldName": "Field1"
                        },
                        "Alias": null
                    },
                    "Conditions": null
                },
                "IsNegated": false,
                "Operator": 5,
                "RightExpression": {
                    "$type": "Tivity.Plugins.Models.ExpressionValue, Tivity.Plugins",
                    "Value": 3
                },
                "RightParentheses": 1,
                "LogicalOperator": 1
            },
            {
                "LeftParentheses": 1,
                "LeftExpression": {
                    "$type": "Tivity.Plugins.Models.ExpressionQuery, Tivity.Plugins",
                    "From": {
                        "ClassName": "TestClass",
                        "Alias": "c"
                    },
                    "Joins": null,
                    "Column": {
                        "Expression": {
                            "$type": "Tivity.Plugins.Models.ExpressionField, Tivity.Plugins",
                            "ClassAlias": null,
                            "FieldName": "Field2"
                        },
                        "Alias": null
                    },
                    "Conditions": null
                },
                "IsNegated": true,
                "Operator": 0,
                "RightExpression": {
                    "$type": "Tivity.Plugins.Models.ExpressionValue, Tivity.Plugins",
                    "Value": "mySearchTxt"
                },
                "RightParentheses": 1,
                "LogicalOperator": 0
            }
        ],
        "Pagination": null
    },
    "Credentials": null,
    "TransactionKey": null
}

3.5 ModelController

For manipulate an instance (or model) the ModelController is responsible. This controller has three methods: create, update and delete.

public async Task<ActionResult<SourceResult<Model>>> Create(ModelCreateRequest request)
{
    return await AdapterWrapper.Instance.Create(request);
}
public async Task<ActionResult<SourceResult>> Update(ModelUpdateRequest request)
{
    return await AdapterWrapper.Instance.Update(request);
}
public async Task<ActionResult<SourceResult>> Delete(ModelDeleteRequest request)
{
    return await AdapterWrapper.Instance.Delete(request);
}

Model / Create

POST https://adapterservice/api/model/create

To create a new instance of a class, the create method can be used.

Request Body

Name
Type
Description

json object

string

The request object needs a class name of an existing class and the new instance as a list of key-value pairs. { "className": "myClass", "model": { "property1": "value1", "property2": "value2" } }

{
  "value": {
    "FieldStr": "value1",
    "FieldInt": 5,
    "FieldDate": "2019-07-29T17:16:42.9744742+02:00",
    "Created": "2019-07-29T18:05:22.0143352+02:00"
  },
  "messages": []
}

Model / Update

PUT https://adapterservice/api/model/update

To manipulate an existing instance usually the update method is used. The ModelUpdateRequest needs the class name and a key for identify the model and the instance itself with all changed properties.

Request Body

Name
Type
Description

json object

string

- className: underlying class of the instance - key: instance identifier - model: properties which are updated { "className": "myClass", "key": { "propertyId": "identifier" }, "model": { "property1": "newValue1", "property2": "newValue2" } }

{
  "messages": []
}

Model / Delete

DELETE https://adapterservice/api/model/delete

For delete an instance (model) call the delete method. The request needs the class name and a key for identify the instance.

Path Parameters

Name
Type
Description

json object

string

- className: underlying class of the instance - key: instance identifier { "className": "myClass", "key": { "propertyId": "identifier" } }

{
  "messages": []
}

3.6 DocumentController

In order to obtain a document you have to use the Download method. As a result, only the content of a document is returned. This is a (byte) stream with the content type information in response header.

public async Task<IActionResult> Download(DocumentDownloadRequest request)

Document / Download

POST https://adapterservice/api/document/download

For download a content you need to send the information about the class and a document identifier. These values are set in the DocumentDowloadRequest. The class name is useful to assign the document content to a certain class. The key value is required to uniquely identify a document. This identifier can be a unique name, a path or a GUID as well.

Request Body

Name
Type
Description

json object

string

- className: name of the assigned class (optional) - key: unique identifier (requred) { "className": "NameOfClass", "key": "identifier" }

Example request (json):

{
  "className": "DummyDocumentClass",
  "key": "75a1bec0-c885-41c7-a93b-59e11441eac5"
}

3.7 FileUpload-StorageController

When files need to be uploaded, the StorageController is also required. This controller ensures that the file stream and an identity key (FileId) are received on server site. The REST service provides for storage the file contents (streams) e.g. save on disk, in database or on memory cache.

public async Task<ActionResult<SourceResult>> Upload([FromForm]StoragePutRequest request)

Storage / Upload

POST https://adapterservice/api/storage/upload

The upload request is a multipart/form-data content-type which consists of the file stream and the formdata FileId.

Request Body

Name
Type
Description

FileId

string

unique identifier of the file

(file) stream

object

the file stream

{
  "messages": []
}

Example execute request for a list of files (json):

{
    "parameters": {
        "parameter1": [
            {
                "FileId": "40765ec8-492f-47ed-9797-f9ff5dc35041",
                "MimeType": "text/plain",
                "FileName": "example01.txt"
            },
            {
                "FileId": "21a3b5da-fd63-4b4c-be43-87a8a07121e2",
                "MimeType": "text/plain",
                "FileName": "example02.txt"
            }
        ]
    }
}

Upload asynchronous calls as sequence diagram:

It is essential for success uploading files that the upload method exist in the REST service and the adapter capability IActionCapability with the execute method was implemented as well. This execute method must be able to process the file parameters accordingly (see example request above).

The available capability types ar listed under the .

The SchemaGetRequest object is currently empty. For more information about the response object see the .

The QueryExecuteRequest object needs a Query with the class ("From"), the columns and a list of conditions. Optional we can add Joins and Paginations. You find a detailed description of the individual properties in the .

Example request (json): For more information about the Query object see the .

For more information about the model methods create, update and delete see the .

For better understanding of the method and the request object see chapter .

During the upload process the platform additionally trigger an execute call (see 3.2 ). There is an entry in the 'parameters' dictionary with the file metadata or a list of files. For Details see the .

SourceAdapter Documentation
ActionController
ISource topic
schema capability documentation
SourceAdapter Documentation
SourceAdapter Documentation about ModelCapability
IDocumentCapability in SourceAdapter
SourceAdapter documentation