Данная страница документация не завершена.

Актуально для версии 1.22.00.

Все действия будут производиться в папке модуля, например, Abills/modules/Portal.
За пример взят модуль Portal.

Старт

Для начала, в корневой папке модуля файл Api.pm, с таким начальным содержанием:

# Мы объявляем package с названием "*модуль*::Api".
package Portal::Api;

=head1 NAME

  Portal Api

=cut

use strict;
use warnings FATAL => 'all';

# Импортируем сообщения для ошибок
use Control::Errors;

my Control::Errors $Errors;

#**********************************************************
=head2 new($db, $conf, $admin, $lang, $debug, $type)

=cut
#**********************************************************
# Создаём конструктор
sub new {
  my ($class, $db, $admin, $conf, $lang, $debug, $type) = @_;

  my $self = {
    db    => $db,
    admin => $admin,
    conf  => $conf,
    lang  => $lang,
    debug => $debug
  };

  bless($self, $class);

  $self->{routes_list} = ();

  # Определяем, для чего роутер вызвал наш модуль API
  # Соответственно, ли это USER API или ADMIN API 
  # И записываем routes_list
  if ($type eq 'user') {
    $self->{routes_list} = $self->user_routes();
  }
  elsif ($type eq 'admin') {
    $self->{routes_list} = $self->admin_routes();
  }

 
  $Errors = Control::Errors->new($self->{db}, $self->{admin}, $self->{conf},
    # Обязательно обозначить что это за модуль,
    # чтобы система могла подгрузить сообщения для ошибок со словаря модуля за потребности
    { lang => $lang, module => 'Portal' }
  ); 

  # Сохраняем словарь ошибок в объект, он нам потом будет нужен 
  $self->{Errors} = $Errors;

  return $self;
}

1;

ADMIN API

Создание роутов

Мы создали обязательное начало для API, теперь, если вам это нужно, создаём роуты для ADMIN API:

#**********************************************************
=head2 admin_routes() - Returns available ADMIN API paths

=cut
#**********************************************************
sub admin_routes {
  my $self = shift;

  return [
    {
      method      => 'GET',
      # Абсолютный путь, за которым можно будет достучаться, например billing.url/api.cgi/portal/attachment
      path        => '/portal/attachment/',
      # Указываем "контроллер" для API /portal/attachment/*
      controller  => 'Portal::Api::admin::Attachment',
      # Даём ссылку на функцию-эндпойнт контроллера
      endpoint    => \&Portal::Api::admin::Attachment::get_portal_attachment,
      credentials => [
		# Определяем нужные параметры для авторизации.
		# ADMIN    - API_KEY
        # ADMINSID - admin_sid по cookie (в том числе для api_call)
        'ADMIN', 'ADMINSID'
      ]
    },
  ]
}

Мы создали свой первый роут, но нам ещё нужно создать для его base первый контроллер.
Вы, конечно, можете писать функцию сразу же в этом хэндлере, но мы не рекомендуем так делать, поскольку в будущем вам станет неудобно это поддерживать.

Создание контроллера

Соответственно, как наши пути будут в /portal/attachment/* и всё что с этим связано, и мы находимся в ADMIN API, то рекомендуем создать файл за такой схемой:
Api/*тип API*/*Контроллер*.pm
например Api/admin/Attachment.pm

Со следующим содержанием:

package Portal::Api::admin::Attachment;

=head1 NAME

  Portal attachment manage
  
  # Рекомендуем в подах записывать к каким
  # группам эндпойнтов относится данный контроллер
  Endpoints:
    /portal/attachment/*

=cut

use strict;
use warnings FATAL => 'all';

use Control::Errors;
# Импортируем объект Portal для работы с базой
# он должен находиться в /usr/abills/Abills/mysql/Portal.pm
use Portal;

my Portal $Portal;
my Control::Errors $Errors;

#**********************************************************
=head2 new($db, $admin, $conf)

=cut
#**********************************************************
sub new {
  my ($class, $db, $admin, $conf, $attr) = @_;

  my $self = {
    db    => $db,
    admin => $admin,
    conf  => $conf,
    attr  => $attr
  };

  bless($self, $class);

  $Portal = Portal->new($db, $admin, $conf);

  # Определяем словарь ошибок, который нам пришёл выше
  $Errors = $self->{attr}->{Errors};

  return $self;
}

#**********************************************************
=head2 get_portal_attachment($path_params, $query_params)
  
  # Всегда пишите в подах Endpoint *METHOD* *path*
  # Это позволит легче искать путь во время разработки.
  Endpoint GET /portal/attachment

=cut
#**********************************************************
sub get_portal_attachment {
  my $self = shift;
  my ($path_params, $query_params) = @_;

  # Определяем системные параметры, сортировки, пагинации
  my %PARAMS = (
    COLS_NAME => 1,
    PAGE_ROWS => $query_params->{PAGE_ROWS} ? $query_params->{PAGE_ROWS} : 25,
    SORT      => ($query_params->{SORT} || 1) > 5 ? 5 : ($query_params->{SORT} || 1),
    PG        => $query_params->{PG} ? $query_params->{PG} : 0,
    DESC      => $query_params->{DESC},
  );

  # Даём возможность сортировки с помощью ?filename&file_size&file_type
  foreach my $param (keys %{$query_params}) {
    $query_params->{$param} = ($query_params->{$param} || "$query_params->{$param}" eq '0')
      ? $query_params->{$param}
      : '_SHOW';
  }

  # Вызываем функцию для извлечения списка из базы, с нашими параметрами и которые определены вызовом
  # которые будут внутри обрабатываться search_former
  my $results = $Portal->attachment_list({
    ID          => '_SHOW',
    FILENAME    => '_SHOW',
    FILE_SIZE   => '_SHOW',
    FILE_TYPE   => '_SHOW',
    UPLOADED_AT => '_SHOW',
    %$query_params,
    %PARAMS,
  });

  # Рекомендация: когда вы создаёте путь, который возвращает массив, то возвращайте 
  # его с объектом с ключём list, а в total возвращайте общее число айтемов - это позволит работать пагинации 
  return {
    list => $results,
    total => $Portal->{TOTAL}
  };
}



USER API

Создание роутов

Если нужно USER API, заполняем и это:

#**********************************************************
=head2 user_routes() - Returns available USER API paths

=cut
#**********************************************************
sub user_routes {
  my $self = shift;

  return [
    {
      method      => 'GET',
      # Для USER API ОБЯЗАТЕЛЬНО начинаем абсолютный путь с /user/*.
      path        => '/user/portal/menu/',
      # Подключаем "контроллер" для API /user/portal/*
      controller  => 'Portal::Api::user::News',
      # Даём ссылку на функцию-эндпойнт контроллера
      endpoint    => \&Portal::Api::user::News::get_user_portal_menu,
      credentials => [
	    # Определяем нужные параметры для авторизации.
        # USER    - авторизация по header, полученном с /user/login
        # USERSID - авторизация по cookie (в том числе для api_call)
        # PUBLIC  - без авторизации
        # Тоесть, в данном случае путь может работать как и с авторизованными пользователями, так и нет.
        # Внутри хэндлера можно определять какой пользователь, об этом ниже.
        'USER', 'USERSID', 'PUBLIC'
      ]
    },
  ]
}


package Portal::Api::user::News;

=head1 NAME 

  User Portal

  # Рекомендуем в подах записывать к каким
  # группам эндпойнтов относится данный контроллер
  
  Endpoints:
    /user/portal/news*
    /user/portal/menu

=cut

use strict;
use warnings FATAL => 'all';

use Control::Errors;
# Импортируем объект Portal для работы с базой
# он должен находиться в /usr/abills/Abills/mysql/Portal.pm
use Portal;

my Portal $Portal;
my Control::Errors $Errors;

#**********************************************************
=head2 new($db, $admin, $conf)

=cut
#**********************************************************
sub new {
  my ($class, $db, $admin, $conf, $attr) = @_;

  my $self = {
    db    => $db,
    admin => $admin,
    conf  => $conf,
    attr  => $attr
  };

  bless($self, $class);

  $Portal = Portal->new($db, $admin, $conf);

  # Определяем словарь ошибок, который нам пришёл выше
  $Errors = $self->{attr}->{Errors};

  return $self;
}

#**********************************************************
=head2 get_user_portal_menu($path_params, $query_params)

  Endpoint GET /user/portal/menu

=cut
#**********************************************************
sub get_user_portal_menu {
  my $self = shift;
  my ($path_params, $query_params) = @_;

  # Не обязательно писать всю логику прямо внутри эндпоинта, как в примере с ADMIN API
  # Вы можете ссылаться на другую функцию, для сокращения использования.
  # Но для простоты понимания, с самого начала лучше писать всё в эндпоинтах
  return $self->_portal_menu({
    # Если пользователь авторизован - в $path_params->{uid} будет UID пользователя.
    UID       => $path_params->{uid} || '',
    DOMAIN_ID => $query_params->{DOMAIN_ID},
    MENU      => 1,
  });
}

1;