8

we want to connect an external fulfillment partner to Magento and want to log their API requests.

Is there any free and open source API logger available?

2

I'll bite since I just recently did this, it was a REST API service however, but something similar for a SOAP request is surely possible. So instead of details, particularly just an overview of the process I took:

1) CREATE A RESOURCE MODEL

First you'll want to create a new Magento resource model, there are plenty of examples out there for such:

Here is an example of the table I'm creating during my modules install (obviously tailor it to suit your needs/requirements).

CREATE TABLE IF NOT EXISTS mynamespace_mymodulename_logs (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `timestamp` datetime NOT NULL,
  `requestUrl` varchar(255) DEFAULT NULL,
  `method` varchar(10) DEFAULT NULL,
  `returnHttpCode` varchar(10) DEFAULT NULL,
  `returnError` TEXT NOT NULL,
  `requestXML` TEXT NOT NULL,
  `responseXML` TEXT NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB  DEFAULT CHARSET=utf8;

Note: I also debated on storing the request and response XML in a gzip format to conserve db space, and XML compresses well. However Magento's adminhtml Grid would need a custom renderer, so I kept the XML being stored as-is for now.

2) GENERIC REST CURL REQUEST VIA PHP

I typically use one single class, for example: Rest.php with something similar for quick and painless API calls via CURL in my module. I believe lib/Varien and Zendframework options may also be something to consider, however I've had great success with this small easy to read snippet:

<?php
$url = 'https://www.google.com';
$method = 'POST';

# headers and data (this is API dependent, some uses XML)
$headers = array(
    'Accept: application/json',
    'Content-Type: application/json',
);
$data = json_encode(array(
    'firstName'=> 'John',
    'lastName'=> 'Doe'
));

$handle = curl_init();
curl_setopt($handle, CURLOPT_URL, $url);
curl_setopt($handle, CURLOPT_HTTPHEADER, $headers);
curl_setopt($handle, CURLOPT_RETURNTRANSFER, true);
curl_setopt($handle, CURLOPT_SSL_VERIFYHOST, false);
curl_setopt($handle, CURLOPT_SSL_VERIFYPEER, false);

switch($method) {
    case 'GET':
        break;
    case 'POST':
        curl_setopt($handle, CURLOPT_POST, true);
        curl_setopt($handle, CURLOPT_POSTFIELDS, $data);
        break;
    case 'PUT': 
        curl_setopt($handle, CURLOPT_CUSTOMREQUEST, 'PUT');
        curl_setopt($handle, CURLOPT_POSTFIELDS, $data);
        break;
    case 'DELETE':
        curl_setopt($handle, CURLOPT_CUSTOMREQUEST, 'DELETE');
        break;
}

$response = curl_exec($handle);
$code = curl_getinfo($handle, CURLINFO_HTTP_CODE);

Source: http://singletonio.blogspot.com/2009/07/simple-php-rest-client-using-curl.html

I also use another separate library called Array2XML for building my POST requests to be used with this simple REST request snippet.

 * @param type $method
 * @param type $data
 * @param type $url
 * @param type $header
 * @param type $topNode
 * @return boolean|xml
 */
public function RESTRequest($method, $url, $header, $data = array(), $topNode = array()) {

Here is a usage example of my Rest.php class: (NOTE: $restUrl, $apiKey are driven from configuration).

// Available Invetory Product
$requestUrl = $restUrl . "inventory/item/test/111/111";
$inventory = Mage::getModel('mynamespace/mymodulename')->RESTRequest('GET', '', $requestUrl, $apiKey);
//zend_debug::dump($inventory->inventory_item->quantity_on_hand);
header("Content-Type: text/xml");
echo $inventory->asXML();
exit;

3) ADD LOGGING TO REQUESTS/RESPONSES

Then wrap your newly created resource model around Rest.php calls to collect data before and after a return has been made from the 3rd party API.

Something like this before curl_exec:

    if (Mage::helper('mymodulename')->getAPILoggingEnable()) {
        $logModel->setData('timestamp', time())
                ->setData('requestUrl', $url)
                ->setData('method', $method)
                ->setData('requestXML', @$postFields);
    }

...

And after the curl_exec:

    $xmlResponse = new SimpleXMLElement($response);

    if ($xmlResponse->error) {
        $logModel->setData('returnError', $xmlResponse->error->error_description);
    }

    if (Mage::helper('mymodulename')->getAPILoggingEnable()) {
        $logModel->setData('returnHttpCode', $code)
                ->setData('responseXML', $xmlResponse->asXML())
                ->save();
    }

Instead of just returning the cURL object I use SimpleXMLElement($response) to convert the APIs response to XML.

A try/catch with a $logModel->save(); and a Mage::logException($e); in the Rest.php can better help debug any issues with the integration. As fatal exceptions will still be partially logged in your resource model but also appear in var/log/excpetions.log

4) ADMIN HTML GRID

Now simply create a new custom Magento adminhtml Grid to your table holding the log data.

My Grid click of line items goes into detail for the single request with the Response and Request XML data as displaying this large of data on the Grid can be problematic.

NOTES

Always add an System -> Configuration option to turn logging on/off as with a large number of requests going through the API communication the table can become quite heavy and effect performance. I will normally disable the logging after the integration has been functioning properly for awhile.

Ideally you could leverage Mage_Log and simply add your custom table to its list of tables to be pruned on intervals to keep it slim, however I'm not sure of the proper procedure for such as specific date/time fields may be required.

You can also consider using custom attributes to store your relational data between Magento and the 3rd Party API.

Hopefully this helps in a general direction of taking the sting out of 3rd party integrations. As not all requirements are ever the same. With that said however a generalized API logging mechanism may be beneficial.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.