Skip to content

Commit

Permalink
Merge pull request #2350 from magento-engcom/async-bulk-webapi
Browse files Browse the repository at this point in the history
[Engcom] Async bulk webapi
  • Loading branch information
vrann authored Apr 6, 2018
2 parents eb09566 + 7711351 commit 3a8b2d6
Show file tree
Hide file tree
Showing 13 changed files with 848 additions and 48 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ public function publishMass($topicName, array $entitiesArray, $groupId = null, $
$requestItems = [];
$bulkException = new BulkException();
foreach ($entitiesArray as $key => $entityParams) {
/** @var \Magento\WebapiAsync\Api\Data\ItemStatusInterface $requestItem */
/** @var \Magento\AsynchronousOperations\Api\Data\ItemStatusInterface $requestItem */
$requestItem = $this->itemStatusInterfaceFactory->create();

try {
Expand Down
6 changes: 2 additions & 4 deletions app/code/Magento/Webapi/Model/Config.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
* @api
* @since 100.0.2
*/
class Config
class Config implements ConfigInterface
{
const CACHE_ID = 'webapi_config';

Expand Down Expand Up @@ -66,9 +66,7 @@ public function __construct(
}

/**
* Return services loaded from cache if enabled or from files merged previously
*
* @return array
* {@inheritdoc}
*/
public function getServices()
{
Expand Down
24 changes: 24 additions & 0 deletions app/code/Magento/Webapi/Model/ConfigInterface.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<?php
/**
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/

declare(strict_types=1);

namespace Magento\Webapi\Model;

/**
* This class gives access to consolidated web API configuration from <Module_Name>/etc/webapi.xml files.
*
* @api
*/
interface ConfigInterface
{
/**
* Return services loaded from cache if enabled or from files merged previously
*
* @return array
*/
public function getServices();
}
10 changes: 6 additions & 4 deletions app/code/Magento/Webapi/Model/Rest/Config.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
namespace Magento\Webapi\Model\Rest;

use Magento\Webapi\Controller\Rest\Router\Route;
use Magento\Webapi\Model\Config as ModelConfig;
use Magento\Webapi\Model\ConfigInterface as ModelConfigInterface;
use Magento\Webapi\Model\Config\Converter;

/**
Expand Down Expand Up @@ -43,11 +43,13 @@ class Config
protected $_routeFactory;

/**
* @param ModelConfig $config
* @param ModelConfigInterface $config
* @param \Magento\Framework\Controller\Router\Route\Factory $routeFactory
*/
public function __construct(ModelConfig $config, \Magento\Framework\Controller\Router\Route\Factory $routeFactory)
{
public function __construct(
ModelConfigInterface $config,
\Magento\Framework\Controller\Router\Route\Factory $routeFactory
) {
$this->_config = $config;
$this->_routeFactory = $routeFactory;
}
Expand Down
1 change: 1 addition & 0 deletions app/code/Magento/Webapi/etc/di.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
*/
-->
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
<preference for="Magento\Webapi\Model\ConfigInterface" type="Magento\Webapi\Model\Config" />
<type name="Magento\Framework\App\AreaList">
<arguments>
<argument name="areas" xsi:type="array">
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
<?php
/**
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/

declare(strict_types=1);

namespace Magento\WebapiAsync\Controller\Rest\Asynchronous;

use Magento\Framework\Webapi\ServiceInputProcessor;
use Magento\Framework\Webapi\Rest\Request as RestRequest;
use Magento\Webapi\Controller\Rest\Router;
use Magento\Webapi\Controller\Rest\ParamsOverrider;
use Magento\Webapi\Controller\Rest\RequestValidator;
use Magento\Webapi\Controller\Rest\InputParamsResolver as WebapiInputParamsResolver;

/**
* This class is responsible for retrieving resolved input data
*/
class InputParamsResolver
{
/**
* @var RestRequest
*/
private $request;
/**
* @var ParamsOverrider
*/
private $paramsOverrider;
/**
* @var ServiceInputProcessor
*/
private $serviceInputProcessor;
/**
* @var Router
*/
private $router;
/**
* @var RequestValidator
*/
private $requestValidator;
/**
* @var \Magento\Webapi\Controller\Rest\InputParamsResolver
*/
private $inputParamsResolver;
/**
* @var bool
*/
private $isBulk;

/**
* Initialize dependencies.
*
* @param \Magento\Framework\Webapi\Rest\Request $request
* @param \Magento\Webapi\Controller\Rest\ParamsOverrider $paramsOverrider
* @param \Magento\Framework\Webapi\ServiceInputProcessor $inputProcessor
* @param \Magento\Webapi\Controller\Rest\Router $router
* @param \Magento\Webapi\Controller\Rest\RequestValidator $requestValidator
* @param \Magento\Webapi\Controller\Rest\InputParamsResolver $inputParamsResolver
* @param bool $isBulk
*/
public function __construct(
RestRequest $request,
ParamsOverrider $paramsOverrider,
ServiceInputProcessor $inputProcessor,
Router $router,
RequestValidator $requestValidator,
WebapiInputParamsResolver $inputParamsResolver,
$isBulk = false
) {
$this->request = $request;
$this->paramsOverrider = $paramsOverrider;
$this->serviceInputProcessor = $inputProcessor;
$this->router = $router;
$this->requestValidator = $requestValidator;
$this->inputParamsResolver = $inputParamsResolver;
$this->isBulk = $isBulk;
}

/**
* Process and resolve input parameters
* Return array with validated input params
* or throw \Exception if at least one request entity params is not valid
*
* @return array
* @throws \Magento\Framework\Exception\InputException if no value is provided for required parameters
* @throws \Magento\Framework\Webapi\Exception
*/
public function resolve()
{
if ($this->isBulk === false) {
return [$this->inputParamsResolver->resolve()];
}
$this->requestValidator->validate();
$webapiResolvedParams = [];
$inputData = $this->request->getRequestData();
foreach ($inputData as $key => $singleEntityParams) {
$webapiResolvedParams[$key] = $this->resolveBulkItemParams($singleEntityParams);
}

return $webapiResolvedParams;
}

/**
* @return \Magento\Webapi\Controller\Rest\Router\Route
*/
public function getRoute()
{
return $this->inputParamsResolver->getRoute();
}

/**
* Convert the input array from key-value format to a list of parameters
* suitable for the specified class / method.
*
* Instead of \Magento\Webapi\Controller\Rest\InputParamsResolver
* we don't need to merge body params with url params and use only body params
*
* @param array $inputData data to send to method in key-value format
* @return array list of parameters that can be used to call the service method
* @throws \Magento\Framework\Exception\InputException if no value is provided for required parameters
* @throws \Magento\Framework\Webapi\Exception
*/
private function resolveBulkItemParams($inputData)
{
$route = $this->getRoute();
$serviceMethodName = $route->getServiceMethod();
$serviceClassName = $route->getServiceClass();
$inputParams = $this->serviceInputProcessor->process($serviceClassName, $serviceMethodName, $inputData);

return $inputParams;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,46 +11,51 @@
use Magento\Framework\Exception\BulkException;
use Magento\Webapi\Controller\Rest\RequestProcessorInterface;
use Magento\Framework\Webapi\Rest\Response as RestResponse;
use Magento\Webapi\Controller\Rest\InputParamsResolver;
use Magento\WebapiAsync\Controller\Rest\Asynchronous\InputParamsResolver;
use Magento\AsynchronousOperations\Model\MassSchedule;
use Magento\AsynchronousOperations\Model\ConfigInterface as WebApiAsyncConfig;
use Magento\Framework\Reflection\DataObjectProcessor;
use Magento\AsynchronousOperations\Api\Data\AsyncResponseInterfaceFactory;
use Magento\AsynchronousOperations\Api\Data\AsyncResponseInterface;

/**
* Responsible for dispatching single and bulk requests.
* Single requests dispatching represented by this class.
* Bulk requests dispatching represented by virtualType of this class.
*/
class AsynchronousRequestProcessor implements RequestProcessorInterface
{
const PROCESSOR_PATH = "/^\\/async(\\/V.+)/";
const BULK_PROCESSOR_PATH = "/^\\/async\/bulk(\\/V.+)/";

/**
* @var \Magento\Framework\Webapi\Rest\Response
*/
private $response;

/**
* @var InputParamsResolver
* @var \Magento\WebapiAsync\Controller\Rest\Asynchronous\InputParamsResolver
*/
private $inputParamsResolver;

/**
* @var MassSchedule
*/
private $asyncBulkPublisher;

/**
* @var WebApiAsyncConfig
*/
private $webapiAsyncConfig;

/**
* @var \Magento\Framework\Reflection\DataObjectProcessor
*/
private $dataObjectProcessor;

/**
* @var AsyncResponseInterfaceFactory
*/
private $asyncResponseFactory;
/**
* @var string Regex pattern
*/
private $processorPath;

/**
* Initialize dependencies.
Expand All @@ -61,21 +66,24 @@ class AsynchronousRequestProcessor implements RequestProcessorInterface
* @param WebapiAsyncConfig $webapiAsyncConfig
* @param DataObjectProcessor $dataObjectProcessor
* @param AsyncResponseInterfaceFactory $asyncResponse
* @param string $processorPath
*/
public function __construct(
RestResponse $response,
InputParamsResolver $inputParamsResolver,
MassSchedule $asyncBulkPublisher,
WebApiAsyncConfig $webapiAsyncConfig,
DataObjectProcessor $dataObjectProcessor,
AsyncResponseInterfaceFactory $asyncResponse
AsyncResponseInterfaceFactory $asyncResponse,
$processorPath = self::PROCESSOR_PATH
) {
$this->response = $response;
$this->inputParamsResolver = $inputParamsResolver;
$this->asyncBulkPublisher = $asyncBulkPublisher;
$this->webapiAsyncConfig = $webapiAsyncConfig;
$this->dataObjectProcessor = $dataObjectProcessor;
$this->asyncResponseFactory = $asyncResponse;
$this->processorPath = $processorPath;
}

/**
Expand All @@ -84,12 +92,12 @@ public function __construct(
public function process(\Magento\Framework\Webapi\Rest\Request $request)
{
$path = $request->getPathInfo();
$path = preg_replace(self::PROCESSOR_PATH, "$1", $path);
$path = preg_replace($this->processorPath, "$1", $path);
$request->setPathInfo(
$path
);

$entitiesParamsArray = [$this->inputParamsResolver->resolve()];
$entitiesParamsArray = $this->inputParamsResolver->resolve();
$topicName = $this->getTopicName($request);

try {
Expand Down Expand Up @@ -133,7 +141,19 @@ public function canProcess(\Magento\Framework\Webapi\Rest\Request $request)
return false;
}

if (preg_match(self::PROCESSOR_PATH, $request->getPathInfo()) === 1) {
if (preg_match($this->processorPath, $request->getPathInfo()) === 1) {
return true;
}
return false;
}

/**
* @param \Magento\Framework\Webapi\Rest\Request $request
* @return bool
*/
public function isBulk(\Magento\Framework\Webapi\Rest\Request $request)
{
if (preg_match(self::BULK_PROCESSOR_PATH, $request->getPathInfo()) === 1) {
return true;
}
return false;
Expand Down
Loading

0 comments on commit 3a8b2d6

Please sign in to comment.