In this blog, you are going to learn “about working with an HTTP client at the Shopware ”.
Some things are not easy to solve without an API. For these cases Shopware 6 has a REST-API.
Shopware 6 comes with a powerful REST-API. You can use this API by using a HTTP-Client, like curl or similar. For reasons of simplicity we wrote a Shopware 6 plugin, but in most cases this is not a good use case. Please do not call the Shopware 6 API through a plugin unless you do have a really good reason to do so!
Let’s create a class that makes use of Guzzle, which is already included in the shopware/core
, so that we can add multiple helpful functions to this class and simplify the use of the API.
RestService.Php
namespace WebkulRestApiHandlingService;
use GuzzleHttpClient;
use GuzzleHttpClient;
class RestService
{
/**
* @var Client
*/
private $restClient;
public function __construct()
{
$this->restClient = new Client();
}
}
Service.Xml
<container xmlns="http://symfony.com/schema/dic/services"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
<services>
<service id="WebkulRestApiHandlingServiceRestService" />
</services>
</container>
The Admin API is secured via OAuth authentication, so we need some helpers to get the authentication token before we do any further requests. Therefore, we extend our RestService
class to do this during the constructor.
namespace WebkulRestApiHandlingService;
use GuzzleHttpClient;
use GuzzleHttpPsr7Request;
use PsrHttpMessageRequestInterface;
use ShopwareCoreSystemSystemConfigSystemConfigService;
class RestService
{
/**
* @var Client
*/
private $restClient;
/**
* @var SystemConfigService
*/
private $config;
/**
* @var string
*/
private $accessToken;
/**
* @var string
*/
private $refreshToken;
/**
* @var DateTimeInterface
*/
private $expiresAt;
public function __construct(SystemConfigService $config)
{
$this->restClient = new Client();
$this->config = $config;
}
private function getAdminAccess(): void
{
$body = json_encode([
'client_id' => 'administration',
'grant_type' => 'password',
'scopes' => $this->config->get('RestApiHandling.config.scope'),
'username' => $this->config->get('RestApiHandling.config.username'),
'password' => $this->config->get('RestApiHandling.config.password')
]);
$request = new Request(
'POST',
getenv('APP_URL') . '/api/oauth/token',
['Content-Type' => 'application/json'],
$body
);
$response = $this->restClient->send($request);
$body = json_decode($response->getBody()->getContents(), true);
$this->setAccessData($body);
}
private function setAccessData(array $body): void
{
$this->accessToken = $body['access_token'];
$this->refreshToken = $body['refresh_token'];
$this->expiresAt = $this->calculateExpiryTime((int) $body['expires_in']);
}
private function calculateExpiryTime(int $expiresIn): DateTimeInterface
{
$expiryTimestamp = (new DateTime())->getTimestamp() + $expiresIn;
return (new DateTimeImmutable())->setTimestamp($expiryTimestamp);
}
private function createShopwareApiRequest(string $method, string $uri, ?string $body = null): RequestInterface
{
return new Request(
$method,
getenv('APP_URL') . '/api/v3/' . $uri,
[
'Authorization' => 'Bearer ' . $this->accessToken,
'Accept' => '*/*'
],
$body
);
}
}
Note our extension of the constructor! First we get the SystemConfigService
to ask for information we can maintain in the administration
.
Since we have changed our RestService
constructor we need to change our services.xml
.
<container xmlns="http://symfony.com/schema/dic/services"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
<services>
<service id="SwagRestApiHandlingServiceRestService">
<argument type="service" id="ShopwareCoreSystemSystemConfigSystemConfigService"/>
</service>
</services>
</container>
Now we need to add a config.xml
to our plugin so that we can maintain the required data information in the administration.
Config.Xml
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="https://raw.githubusercontent.com/shopware/platform/master/src/Core/System/SystemConfig/Schema/config.xsd">
<card>
<title>User Data</title>
<title lang="de-DE">Benutzerdaten</title>
<input-field>
<name>username</name>
<label>Api user name</label>
<label lang="de-DE">API Benutzername</label>
</input-field>
<input-field type="password">
<name>password</name>
<label>Api user password</label>
<label lang="de-DE">API Benutzerpasswort</label>
</input-field>
<input-field type="single-select">
<name>scope</name>
<label>API access level</label>
<label lang="de-DE">API Zugriffslevel</label>
<options>
<option>
<id>write</id>
<name>Write-Access</name>
<name lang="de-DE">Schreibzugriff</name>
</option>
<option>
<id>read</id>
<name>Read-Access</name>
<name lang="de-DE">Lesezugriff</name>
</option>
</options>
</input-field>
</card>
</config>
One of the problems that can occur when working with the Admin API is that your access token has expired. To avoid having to deal with this problem we have already included the refresh token and expiration time in our properties, so let’s start automatically generating a new access token.
class RestService
{
...
private function send(RequestInterface $request, string $uri)
{
if ($this->expiresAt <= (new DateTime())) {
$this->refreshAuthToken();
$body = $request->getBody()->getContents();
$request = $this->createShopwareApiRequest($request->getMethod(), $uri, $body);
}
return $this->restClient->send($request);
}
private function refreshAuthToken(): void
{
$body = json_encode([
'client_id' => 'administration',
'grant_type' => 'refresh_token',
'scopes' => $this->config->get('RestApiHandling.config.scope'),
'refresh_token' => $this->refreshToken
]);
$request = new Request(
'POST',
getenv('APP_URL') . '/api/oauth/token',
['Content-Type' => 'application/json'],
$body
);
$response = $this->restClient->send($request);
$body = json_decode($response->getBody()->getContents(), true);
$this->setAccessData($body);
}
}
<?php
use PsrHttpMessageResponseInterface;
class RestService
{
...
public function request(string $method, string $uri, ?array $body = null): ResponseInterface
{
if ($this->accessToken === null || $this->refreshToken === null || $this->expiresAt === null) {
$this->getAdminAccess();
}
$bodyEncoded = json_encode($body);
$request = $this->createShopwareApiRequest($method, $uri, $bodyEncoded);
return $this->send($request, $uri);
}
}
The request
function makes it easy to send API requests. It requests the API credentials if they do not already exist, and converts your request into a Admin API request.
$this->restService->request(‘GET’, ‘product’);
The first parameter is the HTTP method to be used.
The second parameter is the route / entity name you want to call. Some examples would be product
, rule
or language
.
The third parameter is the data you might want to send to the API. These data can be written as an array
and is encoded by PHP according to the JSON scheme.
I hope it will help you. Thanks for reading. Happy Coding ????
Thank You.