Implement a query
Product Query
An example of a simple query would be asking for some product general information. In this section we will implement the query for getting the product title like so.
Query
query {
product (
id: "413aca742d9af77ce3eb1feec233bb9a"
){
title
}
}
Response
{
"data": {
"product": {
"title": "OX7 Coupé",
}
}
}
Important
Products in OXID eShop are multilanguage models. The language id is not given in the query itself but is set as parameter of the GraphQL endpoint url same as the shop id. So we usually don’t need to think much about handling the shop id or language parameters - shop and GraphQl base module are handling this for us.
File structure
As stated in the Introduction, we need Controller, DataType, Service, Infrastructure and maybe some Exception. Please also have a look at the documentation section about the Architecture of our modules.
├── ..
└── Product
├── Controller
│ └── Product.php
├── DataType
│ └── Product.php
├── Exception
│ └── ProductNotFound.php
├── Infrastructure
│ └── ProductRepository.php
└── Service
└── Product.php
Data type
In the data type we describe all the fields of the product object available for retrieval. In our case we are interested in product id and title:
<?php
declare(strict_types=1);
namespace MyVendor\GraphQL\MyGraph\Product\DataType;
use OxidEsales\Eshop\Application\Model\Article as EshopProductModel;
use TheCodingMachine\GraphQLite\Annotations\Field;
use TheCodingMachine\GraphQLite\Annotations\Type;
use TheCodingMachine\GraphQLite\Types\ID;
/**
* @Type()
*/
final class Product
{
/** @var EshopProductModel */
private $product;
public function __construct(
EshopProductModel $product
) {
$this->product = $product;
}
/**
* @Field()
*/
public function id(): ID
{
return new ID(
$this->product->getId()
);
}
/**
* @Field()
*/
public function title(): string
{
return (string) $this->product->getRawFieldData('oxtitle');
}
}
Repository
The Repository class contains relations to the OXID eShop Core. Ideally this layer should be the only one you need to change if something changes in the shop.
<?php
declare(strict_types=1);
namespace MyVendor\GraphQL\MyGraph\Product\Infrastructure;
use MyVendor\GraphQL\MyGraph\Product\DataType\Product as ProductDataType;
use OxidEsales\Eshop\Application\Model\Article as EshopProductModel;
use OxidEsales\GraphQL\Base\Exception\NotFound;
final class ProductRepository
{
/**
* @throws NotFound
*/
public function product(string $id): ProductDataType
{
/** @var EshopProductModel */
$product = oxNew(EshopProductModel::class);
if (!$product->load($id)) {
throw new NotFound();
}
return new ProductDataType(
$product
);
}
}
Service
The service layer contains the GraphQL module’s business logic. In our case its simple found/not found cases handling:
<?php
declare(strict_types=1);
namespace MyVendor\GraphQL\MyGraph\Product\Service;
use MyVendor\GraphQL\MyGraph\Product\DataType\Product as ProductDataType;
use MyVendor\GraphQL\MyGraph\Product\Exception\ProductNotFound;
use MyVendor\GraphQL\MyGraph\Product\Infrastructure\ProductRepository;
use OxidEsales\GraphQL\Base\Exception\NotFound;
final class Product
{
/** @var ProductRepository */
private $productRepository;
public function __construct(
ProductRepository $productRepository
) {
$this->productRepository = $productRepository;
}
/**
* @throws ProductNotFound
*/
public function product(string $id): ProductDataType
{
try {
$product = $this->productRepository->product($id);
} catch (NotFound $e) {
throw ProductNotFound::byId($id);
}
return $product;
}
}
We’ll throw the ProductNotFound
Exception in case the requested product
cannot be found in the shop. Example of Exception class:
<?php
declare(strict_types=1);
namespace MyVendor\GraphQL\MyGraph\Product\Exception;
use OxidEsales\GraphQL\Base\Exception\NotFound;
use function sprintf;
final class ProductNotFound extends NotFound
{
public static function byId(string $id): self
{
return new self(sprintf('Product was not found by id: %s', $id));
}
}
Controller
The Controller takes the request parameters and links it to the business logic located in the service:
<?php
declare(strict_types=1);
namespace MyVendor\GraphQL\MyGraph\Product\Controller;
use MyVendor\GraphQL\MyGraph\Product\DataType\Product as ProductDataType;
use MyVendor\GraphQL\MyGraph\Product\Service\Product as ProductService;
use TheCodingMachine\GraphQLite\Annotations\Query;
final class Product
{
/** @var ProductService */
private $productService;
public function __construct(
ProductService $productService
) {
$this->productService = $productService;
}
/**
* @Query()
*/
public function product(string $id): ProductDataType
{
return $this->productService->product($id);
}
}
Now we are ready to send a request (you might find more details in Requests) against the API.