Article Custom APIs

Verint Community provides a robust set of in-process APIs that allow developers to interact with its data.  These APIs are accessed through an API service that will return an instance of a class that implements the IApi interface when it's provided the class type.  As a developer you can also create your own APIs and expose them to the API service in the same way you access the community In-Process API.

When Should You Create Your Own API?

APIs are a contract we have with developers developing on our platform.  It is our agreement that we will not change an API in a way that would break an existing integration or customization without providing ample notice.   There are also many vendors, independent software developers and partners who create various custom components for the platform that may want to expose similar API contracts for their products.  For that reason subscribing an API to the API service makes sense as it will allow developers to access the custom API the exact same way as all other APIs.  In previous versions all community APIs were handled via a sealed static class so third party developers had to create their own version of this or an equivalent method in their own code to get to an API.  This made for a disjointed development experience.

If you are creating a small customization not meant for redistribution, or a distributable component that has no public facing API then you don't need to do this.  This feature mainly targets distributable components and core community APIs, however you can use this anytime you want to expose an API through the API service.

Exposing Your API To Verint Community

Implementing the Correct Interface

There are a few considerations you need to take into account when designing your API in order to avoid issues later.  As you will see when you register an interface, an instance of your API is only created when the application right before the plugins initialize which would be when the application starts or the plugins are forced to be reloaded by some internal event.  This means your API class should be stateless or at least only stores data at the instance level that applies to all interactions with the API within the process such as additional dependent services or constant values.   While APIs do not have to be singleton classes, the easiest way to develop them is to approach them like they are.  Your class can also not be static.

You can make your class ready to subscribe to the API service by implementing the IApi interface.  Implementing this interface is easy as it has no properties or methods to implement so other than adding the interface to your class definition it requires no additional work.

In this example we have an API to expose called PersonService and it exposes a method to get a random name.  In order to prepare our class to be included in the API service, we add the IApi interface:

public class PersonService : Telligent.Evolution.Extensibility.Api.IApi
{
    public string GetRandomName()
    {
        return "Wally";
    }
}

If you design all your APIs using your own interfaces and want to be able to refer to your custom interface when loading the API then you can extend your interface with the IApi interface instead of the class implementation itself.  You will then be able to reference your API in the service using your custom interface type OR the concrete class type.

public interface IPersonService : Telligent.Evolution.Extensibility.Api.IApi
{
   string GetRandomName();
}

public class PersonService : IPersonService
{
   public string GetRandomName()
   {
      return "Wally";
   }
}

Registering the Interface

Once you have a class that implements IApi in some fashion, you can register it with the platform.  This is done via the IApiDefinition plugin type.  If you aren't yet familiar with the Plugin model, it is recommended that you review the topics on Plugins.

Aside from the members for IPlugin, IApiDefinition only adds a single method called RegisterApi that gives you an IApiController.  Through the controller you register your API by providing an instance of your class implementing IApi.

public void RegisterApi(IApiController controller)
{
    controller.Add(new PersonService());
}

Using Your API

First compile your project and deploy the project DLL to both the bin folder of Verint Community and the job service folder.  Because IApiDefinition is a plugin, you will need to enable it in the Administration area before it can be used in code.  Assuming it implements no other plugin types you can find it in Administration->Extensions.

 

It is important to understand when APIs are registered in the product life cycle before you attempt to use it to avoid any errors.   The platform registers all APIs before plugins initialize.  This means you can utilize a registered API in a plugin Initialize() method or in any AfterInitialization() method in addition to normal use during the application runtime.  You should avoid using any API in BeforeInitialization() of the plugin life cycle as there is no guarantee an API has been registered.

To use an API, you retrieve it from the API In-Process service using the Get<>() method the same way you would get a built-in in-process API.  In addition to the concrete class, the API service keeps track of an API and its inheritance chain, so if your API uses an abstract class that implements IApi then you can retrieve the API by the abstract class type.  Similarly if you use an interface for your class that extends IApi, you can retrieve it by your custom interface type.

var personAPI = Telligent.Evolution.Extensibility.Apis.Get<PersonService>();

Or because our PersonService implements IPersonService which extends IApi, this is appropriate as well:

var personAPI = Telligent.Evolution.Extensibility.Apis.Get<IPersonService>();

NOTE: When using custom interfaces or abstract classes to extend IApi, you need to remember that the API service can only associate 1 API to a type so you cannot have multiple APIs that use the same abstract class or interface.  If you have a scenario where your APIs share a common interface, the class implementation of that interface should implement IApi.

For example if all your APis use an IRepository interface, then IApi Should be applied to the class implementation:

public interface IRepository { }

public class PersonRepository : IRepository, IApi { }

You could apply it to an interface if the interface extends a shared interface, but the interface itself still should only have a single implementation:

public interface IRepository { }
public interface IPersonRepository : IApi { }
public class PersonRepository : IPersonRepository{ }

It is appropriate to wrap any usage of an API in a null check before its used since an IApiDefinition plugin could have been disabled in Administration(This does not apply to core in-process APIs as they cannot be disabled).

var personAPI = Telligent.Evolution.Extensibility.Apis.Get<IPersonService>();
if (personAPI != null)
{
    //Intract with personAPI
}

Sample

You can download the following sample as a guide.  Once compiled, deployed to your community bin folder, and the plugin SampleAPIDefinition enabled (Administration -> Extensions) it will write "Random Name: Wally" to the event log (Administration->Monitoring->Events) when the plugin initializes.

using Telligent.Evolution.Extensibility;
using Telligent.Evolution.Extensibility.Api;
using Telligent.Evolution.Extensibility.Api.Version1;
using Telligent.Evolution.Extensibility.Version1;

namespace Samples
{
    #region Our API Interface
    public interface IPersonService : Telligent.Evolution.Extensibility.Api.IApi
    {
        string GetRandomName();
    }
    #endregion

    #region Our API Class Implementation of IAPI
    public class PersonService : IPersonService
    {
        public string GetRandomName()
        {
            return "Wally";
        }
    }
    #endregion

    #region IApiDefinition Plugin

    public class SampleAPIDefinition : IApiDefinition
    {
        #region IApiDefinition Members
        public void RegisterApi(IApiController controller)
        {
            //Invoke add on the controller and provide an instance of your class
           controller.Add(new PersonService());
        }
        #endregion


        #region IPlugin Members
        public string Name
        {
            get { return "Sample API Definition"; }
        }

        public string Description
        {
            get { return "A sample API registration plugin"; }
        }

        public void Initialize()
        {
          
            var personAPI = Telligent.Evolution.Extensibility.Apis.Get<IPersonService>();
            var eventLogApi = Telligent.Evolution.Extensibility.Apis.Get<IEventLog>();
            if (personAPI != null && eventLogApi != null)
            {
                //Simply write to the event log
                eventLogApi.Write("Random Name:" + personAPI.GetRandomName(), new EventLogEntryWriteOptions());
            }

        }
        #endregion
    }
    #endregion
}