Tuesday, February 3, 2015

Magento REST API- filtering results

Like in SOAP web services, Magento also offers some kind of filtering results as part of REST web services.

We have sevaral possibilities available as described on official website.

Let's show sample REST request made to Magento (without filters):
 (Skipping part how we get oAuth token and saved it in session, because it is out of scope of this article ...)


<?php

public function getRestDataAction()
    {
        $accessToken = Mage::getSingleton('core/session')->getAccessToken();
        $accessToken = unserialize(base64_decode($accessToken));

        if (!$accessToken) {
            echo 'Access Token invalid!';
            return;
        }

        $oAuthClient = Mage::getModel('apiworks_restclient/oauth_client');
        $params = $oAuthClient->getConfigFromSession();

        //Get REST client object from oAuth token
        $restClient = $accessToken->getHttpClient($params);

        // Set REST resource URL
        $restClient->setUri(sprintf('%s/api/rest/orders', $this->_getSiteUrl()));

        $restClient->setCookie('XDEBUG_SESSION', 'PHPSTORM');

        $restClient->setConfig(array('timeout' => 60));
 
        // In Magento it is neccesary to set json or xml headers in order to work
        $restClient->setHeaders('Accept', 'application/xml');

        // Get method
        $restClient->setMethod(Zend_Http_Client::GET);
        
        //Make REST request
        $response = $restClient->request();
        
        // Here we can see that response body contains json list of products
        $this->getResponse()->setBody($response->getBody());

        return;
    }
Filtering above order list by customer_id would look like this:

<?php

//...

    // Set REST resource URL
    $restClient->setUri(sprintf('%s/api/rest/orders', $this->_getSiteUrl()));

    $restClient->setParameterGet('filter[0][attribute]', 'customer_id');
    $restClient->setParameterGet('filter[0][eq]', '1');

//...
Which will produce URL:
http://siteurl.com/api/rest/orders?filter[0][attribute]=customer_id&filter[0][eq]=1 and return orders filtered by customer_id = 1.

I traced where Magento is using above filters in code in order to get more information about which attributes are available for specific entity and my search ended up in:
 Mage_Api2_Model_Resource around line 724 where all magic with URL parameters is happening:

<?php

final protected function _applyCollectionModifiers(Varien_Data_Collection_Db $collection)
    {
        $pageNumber = $this->getRequest()->getPageNumber();
        if ($pageNumber != abs($pageNumber)) {
            $this->_critical(self::RESOURCE_COLLECTION_PAGING_ERROR);
        }

        $pageSize = $this->getRequest()->getPageSize();
        if (null == $pageSize) {
            $pageSize = self::PAGE_SIZE_DEFAULT;
        } else {
            if ($pageSize != abs($pageSize) || $pageSize > self::PAGE_SIZE_MAX) {
                $this->_critical(self::RESOURCE_COLLECTION_PAGING_LIMIT_ERROR);
            }
        }

        $orderField = $this->getRequest()->getOrderField();

        if (null !== $orderField) {
            $operation = Mage_Api2_Model_Resource::OPERATION_ATTRIBUTE_READ;
            if (!is_string($orderField)
                || !array_key_exists($orderField, $this->getAvailableAttributes($this->getUserType(), $operation))
            ) {
                $this->_critical(self::RESOURCE_COLLECTION_ORDERING_ERROR);
            }
            $collection->setOrder($orderField, $this->getRequest()->getOrderDirection());
        }
        $collection->setCurPage($pageNumber)->setPageSize($pageSize);

        return $this->_applyFilter($collection);
    }
As we can see, this method is handling custom pagination, sort order from provided URL parameters and finally, filtering of result collection by calling '_applyFilter' method:


<?php

    protected function _applyFilter(Varien_Data_Collection_Db $collection)
    {
        $filter = $this->getRequest()->getFilter();

        if (!$filter) {
            return $this;
        }
        if (!is_array($filter)) {
            $this->_critical(self::RESOURCE_COLLECTION_FILTERING_ERROR);
        }
        if (method_exists($collection, 'addAttributeToFilter')) {
            $methodName = 'addAttributeToFilter';
        } elseif (method_exists($collection, 'addFieldToFilter')) {
            $methodName = 'addFieldToFilter';
        } else {
            return $this;
        }
        $allowedAttributes = $this->getFilter()->getAllowedAttributes(self::OPERATION_ATTRIBUTE_READ);

        foreach ($filter as $filterEntry) {
            if (!is_array($filterEntry)
                || !array_key_exists('attribute', $filterEntry)
                || !in_array($filterEntry['attribute'], $allowedAttributes)
            ) {
                $this->_critical(self::RESOURCE_COLLECTION_FILTERING_ERROR);
            }
            $attributeCode = $filterEntry['attribute'];

            unset($filterEntry['attribute']);

            try {
                $collection->$methodName($attributeCode, $filterEntry);
            } catch(Exception $e) {
                $this->_critical(self::RESOURCE_COLLECTION_FILTERING_ERROR);
            }
        }
        return $this;
    }

This one is pretty obvious and here is the place where filters are set on collection.

Now we can put Mage::log here and execute some specific REST api call in order to log list of $allowedAttributes for that specific REST resource.

I hope that this article will be helpful.

Cheers.

, , ,

0 comments:

Post a Comment