С 1.22.00.

В данной статье описано программный интерфейс всего API, как и со стороны модуля так и ядра.


Объект пути

    {
      # HTTP метод, GET, POST, PUT, PATCH, DELETE
      method      => 'POST',
      # Абсолютный путь, за которым можно будет достучаться, например billing.url/api.cgi/portal/articles
      # для USER API обязательно должно начинаться с /user/* 
      # В пути определяются основные параметры, по типу :id, :uid, которое отобразятся в пути
      path        => '/portal/articles/',
      # "Контроллер" для API /portal/articles/*
      controller  => 'Portal::Api::admin::Articles',
      # Ссылка на функцию-эндпойнт контроллера
      endpoint    => \&Portal::Api::admin::Articles::post_portal_articles,
      credentials => [
        # Параметры авторизации ADMIN API
        # ADMIN    - API_KEY
        # ADMINSID - admin_sid по cookie (в том числе для api_call)
        'ADMIN', 'ADMINSID'

        # Параметры авторизации USER API
        # USER    - через header, полученном с /user/login
        # USERSID - через cookie (в том числе для api_call)
        # PUBLIC  - без авторизации 
        # Тоесть, в данном случае путь может работать как и с авторизованными пользователями, так и нет.
        # Внутри хэндлера можно определять какой пользователь.
      ]
    },


Контроллер

# Пэкэдэ <Module>::Api::(admin | user)::<Controller>
package Portal::Api::admin::Articles;

=head1 NAME

  Portal articles manage

  Endpoints:
    /portal/articles/*

=cut

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

# Словарь ошибок
use Control::Errors;

# Грузим нужные депенденси для этого контроллера
use Portal;

# Создаём объект словаря ошибок
my Control::Errors $Errors;

# Создаём объект(ы) депенденси
my Portal $Portal;

# Дополнительно: определяем permissions
my %permissions = ();

# TODO: make this centralized and more maintainable
my @allowed_methods = (5, 6, 10);

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

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

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

  %permissions = %{$attr->{permissions} || {}};

  bless($self, $class);

  # Определяем депенденси
  $Portal = Portal->new($db, $admin, $conf);

  $Errors = $self->{attr}->{Errors};

  return $self;
}

# И дальше пишем пути #

1;


Определение пути

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

  Endpoint DELETE /portal/articles/:id/

=cut
#**********************************************************
sub delete_portal_articles_id {
  my $self = shift;
  my ($path_params, $query_params) = @_;
  # В $path_params находятся переменные которые определены путём
  # Например, /portal/articles/:id/ будет иметь параметр $path_params->{id}

  # в $query_params находятся параметры которые пришли с query
  # например: /portal/articles/?title=test
  # или c json/form body
  # например: POST /portal/articles { "title": "test" }

  my $list = $Portal->portal_articles_list({ ID => $path_params->{id}, COLS_NAME => 1 });

  if (!($list && scalar(@$list))) {
    # Пример пробрасывания ошибки
    return $Errors->throw_error(1440002, { lang_vars => { ID => $path_params->{id} }});
  }

  my $result = $Portal->portal_article_del({ ID => $path_params->{id} });
  if (!$Portal->{errno}) {
    $Attachments->delete_attachment($path_params->{id});
  }

  # Стандартный результат при удалении, должен быть описан в Swagger 
  return $result;
}