0

我最近接手了一个 Perl 客户端的维护工作,该客户端包装了一个 Shipping web 服务。该项目在其初始状态中使用直接映射到 Web 服务对象的 Moo 对象,例如有 Parcel、Address 和 Label 类。

在 API 的 v2 中,您必须将代表这些对象之一的所有数据发布到 Web 服务,然后您会返回该对象的唯一 ID,该 ID 必须用于所有后续事务。

例如,如果我发布:

{ name   => 'Hunter',
  street => '121 Baker St',
  city   => 'New York',
  state  => 'NY',
}

我会取回相同的数据,但包含一个 id:

{ id     => 'adr_xq1411',
  name   => 'Hunter',
  street => '121 Baker St',
  city   => 'New York',
  state  => 'NY',
}

我无法决定如何创建这些对象。目前,我有这个构造函数,它执行实际的 POST 以获取 ID,然后修改当前对象:

sub BUILD {
    my $self = shift;

    my $requestor = Net::Easypost::Request->new;
    my $resp = $requestor->post( 
        '/addresses', 
        $self->serialize( [qw(street1 street2 city state zip)] ) 
    );

    # save the id for this Address from Easypost   
    $self->id( $resp->{id} );

    return $self;
}

在 Perl 中包装 Web 服务时,这是一种常见的方法吗?似乎理想的方法是 POST 到 Web 服务并一次创建 Address 对象的所有属性,但是在 Moo(se) 中,一旦您使用 BUILD 方法,该对象就已经被创建了。

我对包装 Web 服务的习语不是很熟悉,还有比这更简单的方法吗?

任何建议/意见/建议将不胜感激。

4

1 回答 1

4

这当然是一种方法。BUILD将方法分解为角色可能是个好主意。就像是:

package MyApp::PostOnBuild;

use Moo::Role;

has id          => (is => 'rwp');
has endpoint    => (is => 'ro', default => sub { '/addresses' });
has requestor   => (is => 'ro', default => sub { Net::Easypost::Request->new });
has field_names => (is => 'ro', builder => 1);

requires '_build_field_names';
requires 'serialize';  # or maybe just implement serialize within this role!

sub BUILD { }
after BUILD => sub {
    my $self = shift;
    my $resp = $self->requestor->post($self->endpoint, $self->serialize($self->field_names));
    $self->_set_id( $resp->{id} );
};

现在你的类不需要定义自己的BUILD方法。他们需要做的就是:

package MyApp::Address;

use Moo;
with 'MyApp::PostOnBuild';

my @fields = qw/ street1 street2 city state zip /;

has $_ => (is => 'ro') for @fields;

sub _build_field_names { \@fields }

sub serialize { ... }  # would this method be better defined in MyApp::PostOnBuild??

请注意,requestor它现在是一个属性,因此当您测试该类时,您可以执行以下操作:

my $adr = MyApp::Address->new(
    street1   => '123 Example Lane',
    city      => 'Sydney',
    state     => 'NSW',
    zip       => '2035',
    requestor => Test::Requestor->new,
);
于 2014-01-12T21:12:24.983 回答