eBay::API::SimpleBase - Flexible SDK supporting all eBay web services


eBay-API-Simple documentation Contained in the eBay-API-Simple distribution.

Index


Code Index:

NAME

Top

eBay::API::SimpleBase - Flexible SDK supporting all eBay web services

DESCRIPTION

Top

This is the base class for the eBay::API::Simple::* libraries that provide support for all of eBay's web services. This base class does nothing by itself and must be subclassed to provide the complete web service support.

GET THE SOURCE

Top

http://code.google.com/p/ebay-api-simple

PUBLIC METHODS

Top

eBay::API::Simple::{subclass}->new()

see subclass for more docs.

execute( $verb, $call_data )

This method should be supplied by the subclass. This one is only here to provide an example. See actual subclass for docs.

Calling this method will make build and execute the api request.

call verb, i.e. FindItems

hashref of call_data that will be turned into xml.

request_agent

Accessor for the LWP::UserAgent request agent

request_object

Accessor for the HTTP::Request request object

request_content

Accessor for the complete request body from the HTTP::Request object

response_content

Accessor for the HTTP response body content

response_object

Accessor for the HTTP::Request response object

response_dom

Accessor for the LibXML response DOM

response_hash

Accessor for the hashified response content

response_json

Not implemented yet.

nodeContent( $tag, [ $dom ] )

Helper for LibXML that retrieves node content

This is the name of the xml element

optionally a DOM object can be passed in. If no DOM object is passed then the main response DOM object is used.

errors

Accessor to the hashref of errors

has_error

Returns true if the call contains errors

errors_as_string

Returns a string of API errors if there are any.

INTERNAL METHODS

Top

api_config

Accessor to a hashref of api config data that will be used to execute the api call.

  siteid,domain,uri,etc.

api_config_append( $hashref )

This method is used to merge config into the config_api hash

api_config_dump()

This method is used for debugging

errors_append

This method lets you append errors to the errors stack

PRIVATE METHODS

Top

_execute_http_request

This method performs the http request and should be used by each subclass.

_reset

Upon execute() we need to undef any data from a previous call. This method will clear all call data and is usually done before each execute

_build_url( $base_url, $%params )

Constructs a URL based on the supplied args

_get_request_body

The request body should be provided by the subclass

_get_request_headers

The request headers should be provided by the subclass

_get_request_agent

The request request agent should be used by all subclasses

_get_request_object

The request object should be provided by the subclass

_load_yaml_defaults

This method will search for the ebay.yaml file and load configuration defaults for each service endpoint

YAML files can be placed at the below locations. The first file found will be loaded.

  ./ebay.yaml, ~/ebay.yaml, /etc/ebay.yaml 

Sample YAML:

  # Trading - External
  api.ebay.com:
    appid: <your appid>
    certid: <your certid>
    devid: <your devid>
    token: <token>

  # Shopping
  open.api.ebay.com:
    appid: <your appid>
    certid: <your certid>
    devid: <your devid>
    version: 671

  # Finding/Merchandising
  svcs.ebay.com:
    appid: <your appid>
    version: 1.0.0




AUTHOR

Top

Tim Keefer <tim@timkeefer.com>

CONTRIBUTOR

Top

Andrew Dittes <adittes@gmail.com>


eBay-API-Simple documentation Contained in the eBay-API-Simple distribution.
package eBay::API::SimpleBase;

use strict;
use warnings;

use XML::LibXML;
use XML::Simple;
use HTTP::Request;
use HTTP::Headers;
use LWP::UserAgent;
use XML::Parser;
use URI::Escape;
use YAML;
use utf8;

use base 'eBay::API::Simple';

# set the preferred xml simple parser
$XML::Simple::PREFERRED_PARSER = 'XML::Parser';

our $DEBUG = 0;

sub new {
    my $class    = shift;
    my $api_args = shift;

    my $self = {};  
    bless( $self, $class );
    
    # set some defaults 
    $self->api_config->{siteid}   = 0;
    $self->api_config->{enable_attributes} = 0;
    $self->api_config->{timeout}  = 20 unless defined $api_args->{timeout};
    
    unless (defined $api_args->{preserve_namespace}) {
        $self->api_config->{preserve_namespace} = 0;
    }
    
    # set the config args 
    $self->api_config_append( $api_args );
    
    return $self;   
}

sub execute {
    my $self = shift;
    
    $self->{verb}      = shift;
    $self->{call_data} = shift;
    
    if ( ! defined $self->{verb} || ! defined $self->{call_data} ) {
        die "missing verb and call_data";
    }
       
    $self->{response_content} = $self->_execute_http_request();

    # remove xmlns 
    $self->{response_content}  = s/xmlns=["'][^"']+//;

    if ( $DEBUG ) {
        print STDERR $self->request_object->as_string();
        print STDERR $self->response_object->as_string();
    }

}

sub request_agent {
    my $self = shift;
    return $self->{request_agent};
}

sub request_object {
    my $self = shift;
    return $self->{request_object};
}

sub request_content {
    my $self = shift;
    return $self->{request_object}->as_string();
} 

sub response_content {
    my $self = shift;
    return $self->{response_content};
}

sub response_object {
    my $self = shift;
    return $self->{response_object};
}

sub response_dom {
    my $self = shift;

    if ( ! defined $self->{response_dom} ) {
        my $parser = XML::LibXML->new();    
        eval {
            $self->{response_dom} = 
                $parser->parse_string( $self->response_content );
        };
        if ( $@ ) {
            $self->errors_append( { 'parsing_error' => $@ } );
        }
    }

    return $self->{response_dom};
}

sub response_hash {
    my $self = shift;

    if ( ! defined $self->{response_hash} ) {
        $self->{response_hash} = XMLin( $self->response_content,
            forcearray => [],
            keyattr    => []
        );
    }

    return $self->{response_hash};
}

sub response_json {
    my $self = shift;

    if ( ! defined $self->{response_json} ) {
        $self->{response_json} = ''; # xml2json( $self->{response_content} );
    }

    return $self->{response_json};
}

 
sub nodeContent {
    my $self = shift;
    my $tag  = shift;
    my $node = shift;

    $node ||= $self->response_dom();

    return if ! $tag || ! $node;

    my $e = $node->getElementsByTagName($tag);
    if ( defined $e->[0] ) {
        return $e->[0]->textContent();

    }
    else { 
        #print STDERR "no info for $tag\n";
        return;
    }
}

sub errors {
    my $self = shift;
    $self->{errors} = {} unless defined $self->{errors};
    return $self->{errors};
}

sub has_error {
    my $self = shift;
    my $has_error =  (keys( %{ $self->errors } ) > 0) ? 1 : 0;
    return $has_error;
}

sub errors_as_string {
    my $self = shift;

    my @e;
    for my $k ( keys %{ $self->errors } ) {
        push( @e, $k . '-' . $self->errors->{$k} );
    }
    
    return join( "\n", @e );
}

sub api_config {
    my $self = shift;
    $self->{api_config} = {} unless defined $self->{api_config};
    return $self->{api_config};
}

sub api_config_append {
    my $self = shift;
    my $config_hash = shift;

    for my $k ( keys %{ $config_hash } ) {
        $self->api_config->{$k} = $config_hash->{$k};
    }
}

sub api_config_dump {
    my $self = shift;

    my $str;
    
    while ( my( $key, $value ) = each( %{ $self->api_config } ) ) {
         $str .= sprintf( "%s=%s\n", $key, $value );
    }
    
    return $str;
}

sub errors_append {
    my $self = shift;
    my $hashref = shift;

    for my $k ( keys %{ $hashref } ) {
        $self->errors->{$k} = $hashref->{$k};
    }

}

sub _execute_http_request {
    my $self = shift;

    # clear previous call data
    $self->_reset();
 
    unless ( defined $self->{request_agent} ) {
        $self->{request_agent} = $self->_get_request_agent();
    }

    unless ( defined $self->{request_object} ) {
        $self->{request_object} = $self->_get_request_object();
    }

    my $max_tries = 1;
    
    if ( defined $self->api_config->{retry} ) {
        $max_tries =  $self->api_config->{retry} + 1;
    }

    my $content = '';
    my $error   = '';

    for ( my $i=0; $i < $max_tries; ++$i ) {

        my $response = $self->{request_agent}->request( $self->{request_object} );
        $self->{response_object} = $response;

        if ( $response->is_success ) {
            $content   = $response->content();
            
            unless ($self->api_config->{preserve_namespace}) {
                # strip out the namespace param, with single or double quotes
                $content =~ s/xmlns=("[^"]+"|'[^']+') *//;
            }
            
            $self->{response_content} = $content;
            $error     = undef;
            
            # call the classes validate response method if it exists
            $self->_validate_response() if $self->can('_validate_response');
            
            last; # exit the loop
        }
        
        # store the error 
        $error   = $response->status_line;
        $content = $response->content();
    }
  
    $self->errors_append( { http_response => $error } ) if defined $error;     
  
    $self->{response_content} = $content;
    return $content;
}

sub _reset {
    my $self = shift;

    # clear previous call
    $self->{errors}            = undef;
    $self->{response_object}   = undef;
    $self->{response_content}  = undef;
    $self->{request_agent}     = undef;
    $self->{request_object}    = undef;
    $self->{response_dom}      = undef;
    $self->{response_json}     = undef;
    $self->{response_hash}     = undef;

}

sub _build_url {
    my $self = shift;
    my $base = shift;
    my $args = shift;

    my @p;
    for my $k ( keys %{ $args } ) {
        if ( ref( $args->{$k} ) eq 'ARRAY' ) {
            for my $ap ( @{ $args->{$k} } ) {
                push( @p, 
                    ( $k . '=' . uri_escape_utf8( $ap ) ) 
                );                    
            }
        }
        else {
            push( @p, ( $k . '=' . uri_escape_utf8( $args->{$k} ) ) );
        }        
    }

    return( scalar( @p ) > 0 ? $base . '?' . join('&', @p) : $base );
}

sub _get_request_body {
    my $self = shift;
    
    my $xml = "<sample>some content</sample>";

    return $xml; 
}

sub _get_request_headers {
    my $self = shift;
   
    my $obj = HTTP::Headers->new();

    $obj->push_header("SAMPLE-HEADER" => 'foo');
    
    return $obj;
}

sub _get_request_agent {
    my $self = shift;

    my $ua= LWP::UserAgent->new();

    $ua->agent( sprintf( '%s / eBay API Simple (Version: %s)',
        $ua->agent,
        $eBay::API::Simple::VERSION,
    ) );

    # timeout in seconds
    if ( defined $self->api_config->{timeout} ) {
        $ua->timeout( $self->api_config->{timeout} );
    }
    
    # add proxy
    if ( $self->api_config->{http_proxy} ) {
        $ua->proxy( ['http'], $self->api_config->{http_proxy} );
    }

    if ( $self->api_config->{https_proxy} ) {
        $ua->proxy( ['https'], $self->api_config->{https_proxy} );
    }
    
    return $ua;
}

sub _get_request_object {
    my $self = shift;

    my $url = sprintf( 'http%s://%s%s',
        ( $self->api_config->{https} ? 's' : '' ),
        $self->api_config->{domain},
        $self->api_config->{uri}
    );
  
    my $objRequest = HTTP::Request->new(
        "POST",
        $url,
        $self->_get_request_headers,
        $self->_get_request_body
    );

    return $objRequest;
}

sub _load_yaml_defaults {
    my $self = shift;

    return 1 if $self->{_yaml_loaded};
    
    my @files = (
        "./ebay.yaml",
        "/etc/ebay.yaml",
    );

    push(@files, "$ENV{HOME}/ebay.yaml") if defined ($ENV{HOME});

    foreach my $file ( reverse @files ) {

        if ( open( FILE, "<", $file ) ) {

            my $yaml;
            { 
                local $/ = undef; 
                $yaml = <FILE>; 
            }                

            my $hashref = YAML::Load($yaml);
            my $domain  = $self->api_config->{domain};

            if ( defined $hashref->{ $domain } ) {
                $self->api_config_append( $hashref->{ $domain } );
            }
            
            $self->{_yaml_loaded} = 1;
            close FILE;
            last;
        }
    }


}

1;