Adding a new API provider
If you're using a headless commerce system that isn't integrated with Frontastic, you can extend your project to do this. That includes product, content, search, cart, wishlist, and account.
By implementing extensions and integrations in Frontastic, you can use the same interfaces and communication inside the implementation, and it can be used with any API type, for example, REST(ful), GraphQL, or even SOAP.
In this example, we'll add an extension for our products to ABOUT YOU.
- Open the
project.yml
file in the/config
folder of your project - Update the product configuration to the new system, including any access credentials
configuration:
[...]
product:
engine: ABOUT YOU
clientId: YOUR_CLIENT_ID
projectKey: YOUR_PROJECT_KEY
[...]
- Add the below to your
services.xml
in one of your project bundles (if there isn't a bundle yet, you can create one usingbin/console frontastic:create:bundle ProductApi
or see the bundles article for more information)
<service id="AboutYout\ProductApiBundle\Domain\ProductApiFactory"
decorates="Frontastic\Common\ProductApiBundle\Domain\DefaultProductApiFactory">
<argument type="service" id="AboutYou\ProductApiBundle\Domain\ProductApiFactory.inner"/>
</service>
- Create a file called
ProductApiBundle/Domain/ProductApiFactory.php
in the/src/php
folder in your project and add the below code to the file, this integrates with our factory
namespace AboutYou\ProductApiBundle\Domain;
use Frontastic\Common\ProductApiBundle\Domain\ProductApiFactory as BaseProductApiFactory;
use Frontastic\Common\ProductApiBundle\Domain\ProductApi as BaseProductApi;
use Frontastic\Common\ReplicatorBundle\Domain\Project;
class ProductApiFactory implements BaseProductApiFactory
{
private $aggregate;
public function __construct(BaseProductApiFactory $aggregate)
{
$this->aggregate = $aggregate;
}
public function factor(Project $project): BaseProductApi
{
$productConfig = $project->getConfigurationSection('product');
switch ($productConfig->engine) {
case 'ABOUT YOU':
return new ProductApi();
default:
return $this->aggregate->factor($project);
}
}
}
- Then you need to implement the API
A product API must implement the corresponding interface and you can do whatever you want within it. To enable parallel fetching of streams you should always return promises for all data (where documented). Below is an example of what a minimal implementation could look like:
namespace AboutYou\ProductApiBundle\Domain;
use Frontastic\Common\ProductApiBundle\Domain\ProductApi as BaseProductApi;
use Frontastic\Common\ProductApiBundle\Domain\ProductApi\Query\CategoryQuery;
use Frontastic\Common\ProductApiBundle\Domain\ProductApi\Query\ProductQuery;
use Frontastic\Common\ProductApiBundle\Domain\ProductApi\Query\ProductTypeQuery;
use Frontastic\Common\ProductApiBundle\Domain\ProductApi\Result;
use Frontastic\Common\ProductApiBundle\Domain\Product;
use Frontastic\Common\ProductApiBundle\Domain\Variant;
use Frontastic\Common\ProductApiBundle\Domain\Category;
use Frontastic\Common\ProductApiBundle\Domain\ProductType;
use GuzzleHttp\Promise\PromiseInterface;
use GuzzleHttp\Promise\FulfilledPromise;
class ProductApi implements BaseProductApi
{
/**
* @param CategoryQuery $query
* @return Category[]
*/
public function getCategories(CategoryQuery $query): array
{
return [];
}
/**
* @param ProductTypeQuery $query
* @return ProductType[]
*/
public function getProductTypes(ProductTypeQuery $query): array
{
return [];
}
/**
* @param ProductQuery $query
* @param string $mode One of the QUERY_* constants. Execute the query synchronously or asynchronously?
* @return Product|PromiseInterface|null A product or null when the mode is sync and a promise if the mode is async.
*/
public function getProduct(ProductQuery $query, string $mode = self::QUERY_SYNC): ?object
{
return new FulfilledPromise(
new Product([
'name' => 'My Dummy Test Product',
'variants' => [
new Variant(),
],
])
);
}
/**
* @param ProductQuery $query
* @param string $mode One of the QUERY_* constants. Execute the query synchronously or asynchronously?
* @return Result|PromiseInterface A result when the mode is sync and a promise if the mode is async.
*/
public function query(ProductQuery $query, string $mode = self::QUERY_SYNC): object
{
return new FulfilledPromise(
new Result([
'items' => [
new Product([
'name' => 'My Dmmy Test Product',
'variants' => [
new Variant(),
],
]),
],
])
);
}
/**
* Get *dangerous* inner client
*
* This method exists to enable you to use features which aren't part
* of the abstraction layer yet.
*
* Be aware that any usage of this method might seriously impact backwards
* compatibility and the future abstractions might differ a lot from the
* vendor provided abstraction.
*
* Use this with care for features necessary in your customer and talk with
* Frontastic about providing an abstraction.
*
* @return mixed
*/
public function getDangerousInnerClient()
{
return null;
}
}
Updated over 2 years ago