Расширение API через коннектор

Последние изменения: 31.07.2020

Есть возможность расширить API, создав свой коннектор в серверной части платформы.

Более подробно о создании коннектора можно посмотреть здесь.

Для этого при создании коннектор нужно  унаследовать и от интерфейса IApiExtenderPlugin, например:

public class ApiExtenderConnector : IConnector, IApiExtenderPlugin
{
public IList<IApiGroup> ApiGroup { get; private set;}
}

Свойство ApiGroup возвращает массив классов, унаследованных от IApiGroup, которые будут обрабатывать все запросы расширения из внешней системы.

public interface IApiGroup
{
string Id { get; }
object CreateNewEntity();
string GetEntityIdFieldName();
IEnumerable<object> GetList();
object Get(string id);
object Post(object input);
object Put(string id, object input);
void Delete(string id); 
}

Id - идентификатор, который должен быть уникальным в системе. Он может содержать как буквы, так и цифры. Для обращения к этому расширению в url строку нужно будет вставить этот идентификатор, например:

https://localhost:9005/api/v1/Plugins/&lt;идентификатор&gt;

CreateNewEntity - метод для создания новой пользовательской сущности, должен возвращать новый созданный объект.

GetEntityIdFieldName - метод для получения наименования поля, являющимся идентификатором для пользовательской сущности.

GetList - метод получения списка всех пользовательских объектов.

Get(string id) - функция должна возвращать один пользовательский объект по его идентификатору.

Post(object input) - функция для обработки объекта, который пришел из внешней системы методом POST для сохранения. Результатом должен быть обновленный объект после сохранения.

Put(string id, object input) - функция для обработки объекта, который пришел из внешней системы методом PUT для сохранения с точным идентификатором. Результатом должен быть обновленный объект после сохранения.

Delete(string id) - метод для удаления объекта по идентификатору.

На данный момент поддерживаются только одноуровневые сущности с примитивными свойствами. т.е. не поддерживаются вложенные массивы и сущности.

Пример реализации

Создаем пользовательскую сущность:

	 internal class ExtendedEntity 
{
//Идентификатор
public string Id { get; set; }
public string Name { get; set; }
public int ValueInt { get; set; }
public bool ValueBool { get; set; }
}

Создаем обработчик запросов

internal class ApiTestGroup : IApiGroup
{
private List<ExtendedEntity> _list = new List<ExtendedEntity>() {
new ExtendedEntity(){ Id="1",Name="1111"},
new ExtendedEntity(){ Id="2",Name="2223"},
new ExtendedEntity(){ Id="3",Name="3333"}
};
//Идентификатор расширения
public string Id {
get {
return "ApiTestGroup";
}
}
//Описание
public string ApiDescription
{
get
{
return "ApiDescription";
}
}
//Удаление сущности по идентификатору
public void Delete(string id)
{
lock (_list)
{
var exist = _list.FirstOrDefault((t) => t.Id == id);
if (exist != null)
_list.Remove(exist);
}
}
//Получение сущности по идентификатору
public object Get(string id)
{
lock(_list)
return _list.FirstOrDefault((t)=>t.Id==id);
}
//Получение списка всех сущностей для поиска
public IEnumerable<object> GetList()
{
return _list.Select(x=>(object)x);
}
//Создание или редактирование пользовательской сущности
public object Post(object input)
{
lock (_list)
{
var inp = (ExtendedEntity)input;
var exist = _list.FirstOrDefault((t) => t.Id == (inp==null?"": inp.Id));
if (exist != null)
Update((ExtendedEntity)exist, input)
else
_list.Add((ExtendedEntity)input);
}
return input;
}
private void Update(ExtendedEntity exist, object Input) {
exist.Id = ((ExtendedEntity)Input).Id;
exist.Name = ((ExtendedEntity)Input).Name;
exist.ValueInt = ((ExtendedEntity)Input).ValueInt;
exist.ValueBool = ((ExtendedEntity)Input).ValueBool;
}
//Создание или обновление сущности по известному идентификатору
public object Put(string id, object input)
{
lock (_list)
{
_list.Add((ExtendedEntity)input);
}
return input;
}
//Создание новой сущности
public object CreateNewEntity()
{
return new ExtendedEntity();
}
//Имя поля, содержащее идентификатор
public string GetEntityIdFieldName()
{
return "Id";
}
}

Создаем класс коннектора:

	 public class ApiExtenderConnector : IConnector, IApiExtenderPlugin
{
public ApiExtenderConnector() {
ApiGroup = new List<IApiGroup>();
ApiGroup.Add(new ApiTestGroup());
}
public bool IsSelfTimeoutBehavior { get { return false; } }
private string id;
[System.ComponentModel.Description("Идентификатор.")]
public string Id
{
get { return this.id; }
set { this.id = value; }
}
bool initialized = false;
public bool Initialized
{
get
{
return this.initialized;
}
}
private int timeout = 0;
public int Timeout
{
get { return this.timeout; }
set { this.timeout = value; }
}
private bool enabled = true;
public bool Enabled
{
get
{
return this.enabled;
}
set
{
this.enabled = value;
}
}
private TimeoutBehavaior timeoutBehavaior = TimeoutBehavaior.ThrowException;
public TimeoutBehavaior TimeoutBehavaior
{
get { return this.timeoutBehavaior; }
set { this.timeoutBehavaior = value; }
}
public bool IsSupportDeviceInfoInArgs
{get { return false; }
}
[Cleverence.DataCollection.Xml.XmlSerializable(Cleverence.DataCollection.Xml.XmlSerializationType.None)]
public IList<IApiGroup> ApiGroup { get; private set;}
public void CheckLicenseLimitations(List<LicenseExternalSystem> supportedSystems)
{
}
public void Initialize()
{
}
public object InvokeMethod(string methodName, object[] args)
{
return null;
}
}

Далее необходимо откомпилировать и положить готовую библиотеку в папку сервера. В результате после удачного запуска сервера проверяем ответ сервера по пути

https://localhost:&lt;порт базы>/api/v1/

В ответе должна содержаться группа 

{"name":"Plugins/ApiTestGroup","kind":"EntitySet","url":"Plugins/ApiTestGroup"}

Далее при переходе по пути

https://localhost:&lt;порт базы>/api/v1/Plugins/ApiTestGroup

получаем список наших сущностей (результат выполнения функции GetList())

	 {
"@odata.context":"https://localhost:9005/MobileSMARTS/api/v1/$metadata#Plugins&quot;,
"value":[
{"id":"1","name":"1111","valueInt":0,"valueBool":false},
{"id":"2","name":"2223","valueInt":0,"valueBool":false},
{"id":"3","name":"3333","valueInt":0,"valueBool":false}]
}

Далее POST запрос можем проверить в swagger. Для этого заходим

https://localhost:&lt;порт базы>/swagger

Находим там нашу группу Plugins/ApiTestGroup, выбираем POST, вставляем в параметр body:

{"id":"4","name":"new4"}

Нажимаем кнопку “Попробовать!”

Далее заходим в блок GET и видим что наша новая сущность сохранилась:

Для удаления заходим в блок DELETE, вводим наш новый идентификатор 4 и выполняем.

Проверяем в блоке GET и видим, что новая сущность исчезла.