...
Code Block |
---|
language | perl |
---|
title | словарь ошибок Portal::Errors |
---|
|
# Пэкэдж должен ОБЯЗАТЕЛЬНО иметь название *модуль*::Errors
# Это позволяет библиотеке словаря ошибок его же найти
package Portal::Errors;
=head1 NAME
Portal::Errors
# Крайне рекомендуем указывать в pod какой префикс ошибок у модуля.
# Это просто поможет в поддержке, понимать какой префикс у какого модуля.
IDS: 144*
=cut
use strict;
use warnings FATAL => 'all';
#**********************************************************
=head2 errors() - errors list
=cut
#**********************************************************
# Создаём функцию словаря ошибок с анонимным хэшэм.
# В будущем он будет заполнен парами *errno* => *errstr*
sub errors {
return {
# Семизначный код ошибки, с приставкой 144 (модуль Portal) => ключ в словаре ошибки
# ПримерПримеры:
# 1440001 => 'ERR_PORTAL_NO_SENDER',
1440002 => 'ERR_PORTAL_NO_ARTICLE',
};
}
1;
|
Валидатор
Документация по валидатору
Позволяет проверять полученный реквест от клиента по схеме.
Избегает вызова пути с неправильными параметрами, что повышает устойчивость системы и возможных ошибок.
Также позволяет чётко и подробно расписывать какие именно параметры отсутствуют или неправильные в целом.
Создаём корневой файл Validations.pm с таким примерным содержанием:
И не забудьте заполнить lng_english.pl
Code Block |
---|
language | perl |
---|
title | схемы валидатора Portal::Validations |
---|
|
# Называем пэкэдж *модуль*::Validations
package Portal::Validations;
use strict;
use warnings FATAL => 'all';
# Вызываем специальный модуль экспортера, для удобного экспортирования констант с описанием в IDE
use Exporter;
use parent# Заполняем ключи ошибок, можем даже вставлять переменные
$lang{ERR_PORTAL_NO_SENDER} = 'No sender with id %ID%';
$lang{ERR_PORTAL_NO_ARTICLE} = 'No article with id %ID%'; |
Валидатор
Документация по валидатору
Позволяет проверять полученный реквест от клиента по схеме.
Избегает вызова пути с неправильными параметрами, что повышает устойчивость системы и возможных ошибок.
Также позволяет чётко и подробно расписывать какие именно параметры отсутствуют или неправильные в целом.
Создаём корневой файл Validations.pm с таким примерным содержанием:
Code Block |
---|
language | perl |
---|
title | схемы валидатора Portal::Validations |
---|
|
# Называем пэкэдж *модуль*::Validations
package Portal::Validations;
use strict;
use warnings FATAL => 'all';
# Вызываем специальный модуль экспортера, для удобного экспортирования констант с описанием в IDE
use Exporter;
use parent 'Exporter';
# Записываем константы валидации в экспорт
our @EXPORT = qw(
POST_PORTAL_ARTICLES
);
# Записываем константы валидации в экспорт
our @EXPORT_OK = qw(
POST_PORTAL_ARTICLES
);
use constant {
# Называем константу *МЕТОД*_ПУТЬ_
# А подробнее про валидатор можно узнать ссылкой выше.
POST_PORTAL_ARTICLES => {
TITLE => {
required => 1,
type => 'string',
min_length => 5,
max_length => 255
},
DATE => {
required => 1,
type => 'date'
},
PORTAL_MENU_ID => {
required => 1,
type => 'string'
},
SHORT_DESCRIPTION => {
type => 'string',
max_length => 600
},
CONTENT => {
type => 'string',
}
},
};
1;
|
...
Code Block |
---|
|
#**********************************************************
=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) = @_;
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});
}
return $result;
} |
...
Code Block |
---|
|
#**********************************************************
=head2 get_user_portal_news($path_params, $query_params)
Endpoint GET /user/portal/news
=cut
#**********************************************************
sub get_user_portal_news {
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},
PORTAL_MENU_ID => $query_params->{PORTAL_MENU_ID},
MAIN_PAGE => $query_params->{MAIN_PAGE},
LIST => 1
});
} |
Практики
Поиск, сортировка, пагинация
Для правильной работы сортировки мы рекомендуем делать это не вручну, а с помощью search_former которые находятся внутри любого современного модуля.
Он выглядит приблизительно так, с точки зрения пути GET /portal/menus
Code Block |
---|
|
#**********************************************************
=head2 get_portal_menus($path_params, $query_params)
Endpoint GET /portal/menus
=cut
#**********************************************************
sub get_portal_menus {
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} ? $query_params->{SORT} : 1,
PG => $query_params->{PG} ? $query_params->{PG} : 0,
DESC => $query_params->{DESC},
);
foreach my $param (keys %{$query_params}) {
$query_params->{$param} = ($query_params->{$param} || "$query_params->{$param}" eq '0')
? $query_params->{$param}
: '_SHOW';
}
my $list = $Portal->portal_menu_list({
ID => '_SHOW',
NAME => '_SHOW',
URL => '_SHOW',
DATE => '_SHOW',
STATUS => '_SHOW',
# С помощью внутренней деструктуризации присваиваем
%$query_params,
# Оверрайдим параметры
%PARAMS,
});
return {
list => $list,
total => $Portal->{TOTAL}
};
} |
И смотрим что происходит под капотом у portal_menu_list
Code Block |
---|
|
#**********************************************************
=head2 function portal_menu_list() - get menu section list
Arguments:
$attr
Returns:
\@list -
Examples:
my $list = $Portal->portal_menu_list({COLS_NAME=>1});
=cut
#**********************************************************
sub portal_menu_list {
my $self = shift;
my ($attr) = @_;
# Преопределяем параметры, если их нет
my $SORT = ($attr->{SORT}) ? $attr->{SORT} : 1;
my $DESC = ($attr->{DESC}) ? $attr->{DESC} : '';
my $PG = $attr->{PG} ? $attr->{PG} : 0;
my $PAGE_ROWS = $attr->{PAGE_ROWS} ? $attr->{PAGE_ROWS} : 25;
# Эта функция на основе пришедших параметров и паттерном формирует $WHERE clause.
my $WHERE = $self->search_former($attr, [
[ 'ID', 'INT', 'pm.id', 1 ],
[ 'NAME', 'STR', 'pm.name', 1 ],
[ 'URL', 'STR', 'pm.url', 1 ],
[ 'DATE', 'STR', 'DATE(pm.date) as date', 1 ],
[ 'STATUS', 'INT', 'pm.status', 1 ],
], { WHERE => 1 });
$self->query(
"SELECT $self->{SEARCH_FIELDS} pm.id
FROM portal_menu pm
$WHERE
ORDER BY $SORT $DESC LIMIT $PG, $PAGE_ROWS;;",
undef, $attr
);
my $list = $self->{list} || [];
# Берём общий count
$self->query("SELECT COUNT(*) AS total FROM portal_menu pm
$WHERE;",
undef,
{ INFO => 1 }
);
return $list || [];
} |
И вот как раз вы можете в $query_params при вызове делать условный /portal/menu/?url=call*&name=test, и оно соответственно создаст выражения для поиска.
Полностью автоматически!
А насчёт сортирования, есть специальные параметры:
SORT - параметр для сортировки
DESC - по возрастанию или убыванию
А пагинации и лимита:
PG - какая страница
PAGE_ROWS - лимит с таблицы
Это позволяет формировать единые экспрессии по всей системе, без ручного определения.