이것은 권장되지 않습니다. 그것은 내가 그것을 어떻게 할 것인지입니다.
하지만 여전히 각 유형의 오류에 대해이 작업을 수행해야합니다. 기본적으로이 귀결 : 응답의 그 종류
. 구성 방법은 Refer to one of them입니다. 여기에 예제가 있습니다. *Catalyst::Controller::REST::status_teapot = sub {
my $self = shift;
my $c = shift;
my %p = Params::Validate::validate(@_, { message => { type => SCALAR }, },);
$c->response->status(418);
$c->log->debug("Status I'm A Teapot: " . $p{'message'}) if $c->debug;
$self->_set_entity($c, { error => $p{'message'} });
return 1;
}
당신이 행동을 많이 가지고 있기 때문에 그 너무 지루한 경우
, 내가 의도처럼 당신이 end
행동의 사용을 권장합니다. 그 방법에 대한 자세한 내용은 아래에서 조금 더 자세히 설명합니다. 그런 경우 Try :: Tiny 구문을 동작에 추가하지 마십시오. 대신 사용중인 모든 모델 또는 다른 모듈이 좋은 예외를 throw하는지 확인하십시오.각각의 경우에 대한 예외 클래스를 생성하고 어떤 경우에 발생해야하는지에 대한 제어를 전달합니다.
이 모든 작업을 수행하는 좋은 방법은 Catalyst::ControllerRole::CatchErrors을 사용하는 것입니다. 오류를 처리 할 catch_error
메서드를 정의 할 수 있습니다. 이 방법에서는 어떤 예외가 어떤 종류의 응답을 야하는지 알아내는 디스패치 테이블을 작성합니다. 여기에 몇 가지 중요한 정보가 있으므로 documentation of $c->error
을보십시오.
package MyApp::Controller::Root;
use Moose;
use Safe::Isa;
BEGIN { extends 'Catalyst::Controller::REST' }
with 'Catalyst::ControllerRole::CatchErrors';
__PACKAGE__->config(
json_options => { relaxed => 1, allow_nonref => 1 },
default => 'application/json',
map => { 'application/json' => [qw(View JSON)] },
);
sub default : Path : ActionClass('REST') { }
sub default_GET {
my ($self, $c, $mid) = @_;
$c->model('Foo')->frobnicate;
}
sub catch_errors : Private {
my ($self, $c, @errors) = @_;
# Build a callback for each of the exceptions.
# This might go as an attribute on $c in MyApp::Catalyst as well.
my %dispatch = (
'MyApp::Exception::BadRequest' => sub {
$c->status_bad_request(message => $_[0]->message);
},
'MyApp::Exception::Teapot' => sub {
$c->status_teapot;
},
);
# @errors is like $c->error
my $e = shift @errors;
# this might be a bit more elaborate
if (ref $e =~ /^MyAPP::Exception/) {
$dispatch{ref $e}->($e) if exists $dispatch{ref $e};
$c->detach;
}
# if not, rethrow or re-die (simplified)
die $e;
}
위
은 조, 안된 예이다. 정확히 이렇게 작동하지 않을 수도 있지만 좋은 시작입니다. 디스 패칭을 주 Catalyst 응용 프로그램 객체 (컨텍스트 $c
)의 속성으로 이동하는 것이 좋습니다. 그것을하기 위해 MyApp :: Catalyst에 배치하십시오. package MyApp::Catalyst;
# ...
has error_dispatch_table => (
is => 'ro',
isa => 'HashRef',
traits => 'Hash',
handles => {
can_dispatch_error => 'exists',
dispatch_error => 'get',
},
builder => '_build_error_dispatch_table',
);
sub _build_error_dispatch_table {
return {
'MyApp::Exception::BadRequest' => sub {
$c->status_bad_request(message => $_[0]->message);
},
'MyApp::Exception::Teapot' => sub {
$c->status_teapot;
},
};
}
그리고는 다음과 같이 파견을 수행
$c->dispatch_error(ref $e)->($e) if $c->can_dispatch_error(ref $e);
지금 당신이 필요로하는 모든 좋은 예외입니다. 이를 수행하는 데는 여러 가지 방법이 있습니다. 나는 Exception::Class 또는 Throwable::Factory을 좋아한다.
package MyApp::Model::Foo;
use Moose;
BEGIN { extends 'Catalyst::Model' };
# this would go in its own file for reusability
use Exception::Class (
'MyApp::Exception::Base',
'MyApp::Exception::BadRequest' => {
isa => 'MyApp::Exception::Base',
description => 'This is a 400',
fields => [ 'message' ],
},
'MyApp::Exception::Teapot' => {
isa => 'MyApp::Exception::Base',
description => 'I do not like coffee',
},
);
sub frobnicate {
my ($self) = @_;
MyApp::Exception::Teapot->throw;
}
다시 말해서 예외를 자체 모듈로 옮겨서 어디에서나 재사용 할 수 있습니다. 이것은 훌륭하게 확장 될 수 있습니다. 비즈니스 로직이나 모델을 웹 앱이라는 사실에 너무 강하게 결합하는 것은 나쁜 디자인이라는 점도 명심하십시오. 그런 식으로 설명하기 쉽기 때문에 아주 예외적 인 이름을 사용하기로했습니다. 좀 더 일반적이고 덜 웹 중심적인 이름을 원할 수도 있습니다. 그리고 당신의 디스패치 이름은 실제로 그것들을 매핑해야합니다. 그렇지 않으면 웹 레이어에 너무 많이 묶여 있습니다.
1) 예, 이것은 복수형입니다. here을 참조하십시오.
우수 답변, 매우 철저히 답변 해 주셔서 감사합니다. 나는'Catalyst :: ControllerRole :: CatchErrors' 소스를 살펴 봤고'before 'end'=> sub {...}'를 사용했다. 유일한 문제는'@ error' 객체가 REST 컨트롤러 클래스에 의해 아마도 추가 된'App :: API :: Foo-> default ...에 잡힌 예외 '와 같은 문자열에 래핑되어 예외가 될 수 없다는 것입니다 쉽게 파견. – ojosilva
@ojosilva 흠, 그건 나쁘군요. 거기에 실제 물건이 없습니까? 아니면 그냥 죽었 니? – simbabque
내가 사용하고있는이 새로운 REST API가 사용되기 전에 존재하는 내 모델은 '죽는다'라는 말을 많이 사용합니다. 액션별로 Try :: Tiny 액션을 사용하는 것은 좋은 옵션이 아니지만, 내부 모델 에러가 외부 메시지 문자열로 싸여있는 것을 피할 수있는 유일한 방법 일 수 있습니다. – ojosilva