{"id":526044,"date":"2026-02-27T13:35:53","date_gmt":"2026-02-27T13:35:53","guid":{"rendered":"https:\/\/webkul.com\/blog\/?p=526044"},"modified":"2026-02-27T13:36:01","modified_gmt":"2026-02-27T13:36:01","slug":"how-to-use-symfony-http-prestashop-9","status":"publish","type":"post","link":"https:\/\/webkul.com\/blog\/how-to-use-symfony-http-prestashop-9\/","title":{"rendered":"How to Use Symfony HTTP Client in PrestaShop 9"},"content":{"rendered":"\n<p>PrestaShop 9 marks a shift in architecture by officially removing Guzzle from its core dependencies. <\/p>\n\n\n\n<p>For years, Guzzle was the standard for HTTP communication in the PHP ecosystem. However, as PrestaShop moves on\u00a0to <strong>Symfony 6.4 LTS<\/strong>, the platform now standardizes on the native\u00a0<strong>Symfony HTTP Client<\/strong>.<\/p>\n\n\n\n<p>While shifting away from a familiar tool might feel disruptive at first.<\/p>\n\n\n\n<p>It is actually a strategic opportunity to modernize your module codebase, making it leaner, faster, and deeply integrated with Symfony&#8217;s service container.<\/p>\n\n\n\n<p>In this blog, we will build a complete, installable module from scratch that demonstrates exactly how to integrate external APIs the &#8220;<strong>PrestaShop 9 way<\/strong>&#8221; using <strong>Dependency Injection<\/strong> and <strong>Services<\/strong>.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Architecture Shift: Procedural \u2192 Service-Oriented<\/h3>\n\n\n\n<p>The most important conceptual change in PrestaShop 9 is moving from&nbsp;<strong>tightly coupled, procedural code<\/strong>&nbsp;inside hooks to&nbsp;<strong>clean service-oriented architecture<\/strong>&nbsp;powered by Dependency Injection.<\/p>\n\n\n\n<p><strong>Before PrestaShop 9:<\/strong><\/p>\n\n\n\n<p>In previous versions, it was common to instantiate HTTP clients directly inside hook methods or controllers. This made the code hard to test, reuse, or maintain:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\">\/\/ Old approach - Business logic, HTTP calls, and error handling all mixed together\npublic function hookActionValidateOrder(array $params): void\n{\n    $client = new GuzzleHttp\\Client(&#091;\n        &#039;base_uri&#039; =&gt; &#039;https:\/\/api.shipping.com&#039;,\n        &#039;timeout&#039;  =&gt; 10,\n    ]);\n\n    $response = $client-&gt;post(&#039;\/shipments&#039;, &#091;\n        &#039;json&#039; =&gt; &#091;&#039;order_id&#039; =&gt; $params&#091;&#039;id_order&#039;]],\n    ]);\n\n    $data = json_decode($response-&gt;getBody(), true);\n    \/\/ ... process $data\n}<\/pre>\n\n\n\n<p><strong>PrestaShop 9:<\/strong><\/p>\n\n\n\n<p>PrestaShop 9 embraces the&nbsp;<strong>Service Container<\/strong>&nbsp;pattern. Your hook method or controllers should do one thing: delegate to a service. HTTP logic lives in a dedicated, injectable, testable service class.<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\">\/\/ Good: The hook delegates to a clean service\npublic function hookActionValidateOrder(array $params): void\n{\n    $container      = SymfonyContainer::getInstance();\n    $shippingService = $container-&gt;get(ShippingApiService::class);\n\n    try {\n        $shipment = $shippingService-&gt;createShipment($params&#091;&#039;id_order&#039;]);\n        \/\/ Clean business logic only\n    } catch (ShippingException $e) {\n        $this-&gt;handleShippingError($e);\n    }\n}<\/pre>\n\n\n\n<figure class=\"wp-block-image size-full\"><img decoding=\"async\" width=\"880\" height=\"196\" src=\"https:\/\/cdnblog.webkul.com\/blog\/wp-content\/uploads\/2026\/02\/servicearchitectureflow.webp\" alt=\"servicearchitectureflow\" class=\"wp-image-527293\" srcset=\"https:\/\/cdnblog.webkul.com\/blog\/wp-content\/uploads\/2026\/02\/servicearchitectureflow.webp 880w, https:\/\/cdnblog.webkul.com\/blog\/wp-content\/uploads\/2026\/02\/servicearchitectureflow-300x67.webp 300w, https:\/\/cdnblog.webkul.com\/blog\/wp-content\/uploads\/2026\/02\/servicearchitectureflow-250x56.webp 250w, https:\/\/cdnblog.webkul.com\/blog\/wp-content\/uploads\/2026\/02\/servicearchitectureflow-768x171.webp 768w\" sizes=\"(max-width: 880px) 100vw, 880px\" loading=\"lazy\" \/><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\">Building the Module Step by Step<\/h2>\n\n\n\n<p>Let&#8217;s build\u00a0<strong>wkdailyquote<\/strong> a complete, installable module that fetches a random quote from an external API and displays it on the PrestaShop dashboard. <\/p>\n\n\n\n<p>Following the full PS 9 architecture: DI, services, DTOs, caching, and error handling.<\/p>\n\n\n\n<p><strong>Module Location<\/strong>: Create a folder named&nbsp;<strong>wkdailyquote<\/strong>&nbsp;inside your PrestaShop&nbsp;<strong>\/modules\/<\/strong>&nbsp;directory before starting.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Step 1: Define Composer Autoloading<\/h4>\n\n\n\n<pre class=\"EnlighterJSRAW\">{\n    &quot;name&quot;: &quot;wk\/wkdailyquote&quot;,\n    &quot;type&quot;: &quot;prestashop-module&quot;,\n    &quot;require&quot;: {\n        &quot;php&quot;: &quot;&gt;=8.1&quot;\n    },\n    &quot;autoload&quot;: {\n        &quot;psr-4&quot;: {\n            &quot;WkDailyQuote\\\\&quot;: &quot;src\/&quot;\n        }\n    },\n    &quot;config&quot;: {\n        &quot;prepend-autoloader&quot;: false\n    }\n}<\/pre>\n\n\n\n<p>Now, navigate to&nbsp;<code>\/modules\/wkdailyquote\/<\/code>&nbsp;in your terminal and run:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\">composer dump-autoload<\/pre>\n\n\n\n<h4 class=\"wp-block-heading\">Step 2: Create the Data Transfer Object (DTO)<\/h4>\n\n\n\n<p>A DTO provides a&nbsp;<strong>type-safe, validated data structure<\/strong>&nbsp;for the API response. Instead of working with raw arrays throughout your codebase, you pass strongly-typed&nbsp;objects.<\/p>\n\n\n\n<p><strong>File:<\/strong>&nbsp;<code>\/modules\/wkdailyquote\/src\/DTO\/Quote.php<\/code><\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\">&lt;?php\n\nnamespace WkDailyQuote\\DTO;\n\nclass Quote\n{\n    public function __construct(\n        private int    $id,\n        private string $quote,\n        private string $author\n    ) {\n        if (empty($quote)) {\n            throw new \\InvalidArgumentException(&#039;Quote cannot be empty&#039;);\n        }\n        if (empty($author)) {\n            throw new \\InvalidArgumentException(&#039;Author cannot be empty&#039;);\n        }\n    }\n    public static function fromArray(array $data): self\n    {\n        if (!isset($data&#091;&#039;id&#039;], $data&#091;&#039;quote&#039;], $data&#091;&#039;author&#039;])) {\n            throw new \\InvalidArgumentException(&#039;Invalid API response structure&#039;);\n        }\n        return new self((int)$data&#091;&#039;id&#039;], $data&#091;&#039;quote&#039;], $data&#091;&#039;author&#039;]);\n    }\n    public function getId(): int\n    {\n        return $this-&gt;id;\n    }\n    public function getQuote(): string\n    {\n        return $this-&gt;quote;\n    }\n    public function getAuthor(): string\n    {\n        return $this-&gt;author;\n    }\n    public function toArray(): array\n    {\n        return &#091;&#039;id&#039; =&gt; $this-&gt;id, &#039;quote&#039; =&gt; $this-&gt;quote, &#039;author&#039; =&gt; $this-&gt;author];\n    }\n}<\/pre>\n\n\n\n<h4 class=\"wp-block-heading\">Step 3: Create Custom Exception Classes<\/h4>\n\n\n\n<p>Instead of catching a generic <code>\\Exception<\/code> everywhere, create your own API-specific exception class (or small exception hierarchy). <\/p>\n\n\n\n<p>Using named factory methods (like <code>ApiException::networkError()<\/code> or <code>ApiException::invalidResponse()<\/code>) also makes your <code>throw<\/code> statements clearer and easier to understand.<\/p>\n\n\n\n<p><strong>File:<\/strong>&nbsp;<code>\/modules\/wkdailyquote\/src\/Exception\/ApiException.php<\/code><\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\">&lt;?php\n\nnamespace WkDailyQuote\\Exception;\n\nclass ApiException extends \\Exception\n{\n    public static function networkError(string $message, ?\\Throwable $prev = null): self\n    {\n        return new self(&quot;Network error: $message&quot;, 0, $prev);\n    }\n\n    public static function httpError(int $statusCode, string $url): self\n    {\n        return new self(&quot;HTTP $statusCode error when accessing $url&quot;);\n    }\n\n    public static function invalidResponse(string $message): self\n    {\n        return new self(&quot;Invalid API response: $message&quot;);\n    }\n}<\/pre>\n\n\n\n<h4 class=\"wp-block-heading\">Step 4: Build the Cache Manager Service<\/h4>\n\n\n\n<p>Calling an external API on every page load is slow and wastes rate limit quota. The&nbsp;QuoteCacheManager&nbsp;wraps PrestaShop&#8217;s built-in cache system with a clean interface.<\/p>\n\n\n\n<p><strong>File:<\/strong>&nbsp;<code>\/modules\/wkdailyquote\/src\/Service\/QuoteCacheManager.php<\/code><\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\">&lt;?php\n\nnamespace WkDailyQuote\\Service;\n\nuse WkDailyQuote\\DTO\\Quote;\n\nclass QuoteCacheManager\n{\n    private const CACHE_KEY = &#039;wkdailyquote_current&#039;;\n    private const CACHE_TTL = 3600;\n\n    public function get(): ?Quote\n    {\n        $cached = \\Cache::getInstance()-&gt;get(self::CACHE_KEY);\n\n        return $cached ? Quote::fromArray($cached) : null;\n    }\n\n    public function set(Quote $quote): void\n    {\n        \\Cache::getInstance()-&gt;set(self::CACHE_KEY, $quote-&gt;toArray(), self::CACHE_TTL);\n    }\n\n    public function clear(): void\n    {\n        \\Cache::getInstance()-&gt;delete(self::CACHE_KEY);\n    }\n}<\/pre>\n\n\n\n<h4 class=\"wp-block-heading\">Step 5: Build the API Service (The Heart of the Module)<\/h4>\n\n\n\n<p>Here\u00a0<strong>Symfony HTTP Client<\/strong>\u00a0is actually used. The\u00a0QuoteFetcher\u00a0service receives the client via\u00a0<strong>constructor injection<\/strong>, it never instantiates it directly. This is the key difference from the old approach.<\/p>\n\n\n\n<p>Notice how Symfony&#8217;s&nbsp;$response-&gt;toArray()&nbsp;handles JSON parsing automatically, and how each error type maps cleanly to a specific exception class via Symfony&#8217;s exception hierarchy.<\/p>\n\n\n\n<p><strong>File:<\/strong>&nbsp;<code>\/modules\/wkdailyquote\/src\/Service\/QuoteFetcher.php<\/code><\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\">&lt;?php\n\nnamespace WkDailyQuote\\Service;\n\nuse WkDailyQuote\\DTO\\Quote;\nuse WkDailyQuote\\Exception\\ApiException;\nuse WkDailyQuote\\Service\\QuoteCacheManager;\nuse Symfony\\Contracts\\HttpClient\\HttpClientInterface;\nuse Symfony\\Contracts\\HttpClient\\Exception\\TransportExceptionInterface;\n\nclass QuoteFetcher\n{\n    private const API_URL = &#039;https:\/\/dummyjson.com\/quotes\/random&#039;;\n    private const TIMEOUT = 5;\n    private const MAX_RETRIES = 2;\n\n    public function __construct(\n        private readonly HttpClientInterface $httpClient,\n        private readonly QuoteCacheManager   $cacheManager\n    ) {\n    }\n\n    public function getRandomQuote(): ?Quote\n    {\n        if ($cached = $this-&gt;cacheManager-&gt;get()) {\n            return $cached;\n        }\n\n        try {\n            $quote = $this-&gt;fetchWithRetry();\n            $this-&gt;cacheManager-&gt;set($quote);\n            return $quote;\n        } catch (ApiException $e) {\n            \\PrestaShopLogger::addLog(&quot;&#091;WkDailyQuote] {$e-&gt;getMessage()}&quot;, 3);\n            return null;\n        }\n    }\n\n    private function fetchWithRetry(): Quote\n    {\n        for ($attempt = 1; $attempt &lt;= self::MAX_RETRIES; $attempt++) {\n            try {\n                return $this-&gt;makeRequest();\n            } catch (ApiException $e) {\n                if ($attempt &lt; self::MAX_RETRIES) {\n                    usleep(pow(2, $attempt) * 100000);\n                }\n                $last = $e;\n            }\n        }\n        throw $last;\n    }\n\n    private function makeRequest(): Quote\n    {\n        try {\n            $response = $this-&gt;httpClient-&gt;request(&#039;GET&#039;, self::API_URL, &#091;\n                &#039;timeout&#039; =&gt; self::TIMEOUT,\n                &#039;headers&#039; =&gt; &#091;&#039;Accept&#039; =&gt; &#039;application\/json&#039;],\n            ]);\n\n            if ($response-&gt;getStatusCode() !== 200) {\n                throw ApiException::httpError($response-&gt;getStatusCode(), self::API_URL);\n            }\n\n            return Quote::fromArray($response-&gt;toArray());\n        } catch (TransportExceptionInterface $e) {\n            throw ApiException::networkError($e-&gt;getMessage(), $e);\n        } catch (\\InvalidArgumentException $e) {\n            throw ApiException::invalidResponse($e-&gt;getMessage());\n        }\n    }\n}<\/pre>\n\n\n\n<h4 class=\"wp-block-heading\">Step 6: Configure Dependency Injection<\/h4>\n\n\n\n<p>This YAML file is where the magic happens. It tells Symfony&#8217;s container\u00a0<em>how to wire everything together<\/em>. <\/p>\n\n\n\n<p>The container sees that\u00a0QuoteFetcher\u00a0needs an\u00a0HttpClientInterface, so it automatically injects the built-in\u00a0@http_client\u00a0service \u2014 you never instantiate it yourself.<\/p>\n\n\n\n<p><strong>File:<\/strong>&nbsp;<code>\/modules\/wkdailyquote\/config\/services.yml<\/code><\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\">services:\n  _defaults:\n    autowire: true\n    autoconfigure: true\n    public: false\n\n  WkDailyQuote\\:\n    resource: &#039;..\/src\/*&#039;\n    exclude:  &#039;..\/src\/{index.php,DTO}&#039;\n\n  WkDailyQuote\\Service\\QuoteCacheManager:\n    public: true\n\n  WkDailyQuote\\Service\\QuoteFetcher:\n    public: true\n    arguments:\n      $httpClient:   &#039;@http_client&#039;\n      $cacheManager: &#039;@WkDailyQuote\\Service\\QuoteCacheManager&#039;<\/pre>\n\n\n\n<h4 class=\"wp-block-heading\">Step 7: Create the Main Module File<\/h4>\n\n\n\n<p>The main\u00a0<strong>wkdailyquote.php<\/strong>\u00a0file registers hooks, resolves services from the container, and delegates all real work to them. <\/p>\n\n\n\n<p>Notice there is no HTTP code here whatsoever, that separation of concerns is exactly the goal.<\/p>\n\n\n\n<p><strong>File:<\/strong>&nbsp;<code>\/modules\/wkdailyquote\/<code>wkdailyquote<\/code>.php<\/code><\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\">&lt;?php\n\nrequire_once __DIR__ . &#039;\/vendor\/autoload.php&#039;;\n\nuse PrestaShop\\PrestaShop\\Adapter\\SymfonyContainer;\nuse WkDailyQuote\\Service\\QuoteFetcher;\nuse WkDailyQuote\\Service\\QuoteCacheManager;\n\nclass WkDailyQuote extends Module\n{\n    public function __construct()\n    {\n        $this-&gt;name = &#039;wkdailyquote&#039;;\n        $this-&gt;tab = &#039;administration&#039;;\n        $this-&gt;version = &#039;1.0.0&#039;;\n        $this-&gt;author = &#039;wk&#039;;\n        $this-&gt;need_instance = 0;\n        $this-&gt;ps_versions_compliancy = &#091;\n            &#039;min&#039; =&gt; &#039;9.0.0&#039;,\n            &#039;max&#039; =&gt; _PS_VERSION_\n        ];\n        $this-&gt;bootstrap = true;\n\n        parent::__construct();\n\n        $this-&gt;displayName = $this-&gt;l(&#039;Daily Quote&#039;);\n        $this-&gt;description = $this-&gt;l(&#039;Displays inspirational quotes on your dashboard using Symfony HTTP Client with caching.&#039;);\n        $this-&gt;confirmUninstall = $this-&gt;l(&#039;Are you sure you want to uninstall this module?&#039;);\n    }\n\n    public function install(): bool\n    {\n        return parent::install()  &amp;&amp; $this-&gt;registerHook(&#039;displayDashboardTop&#039;);\n    }\n\n    public function uninstall(): bool\n    {\n        $this-&gt;clearModuleCache();\n\n        return parent::uninstall();\n    }\n\n    public function hookDisplayDashboardTop(array $params)\n    {\n        if ($this-&gt;context-&gt;controller-&gt;controller_name != &#039;AdminDashboard&#039;) return;\n\n        $container = SymfonyContainer::getInstance();\n\n        if (!$container-&gt;has(QuoteFetcher::class)) {\n            return &#039;&#039;;\n        }\n\n        $quote = $container-&gt;get(QuoteFetcher::class)-&gt;getRandomQuote();\n\n        if (!$quote) {\n            return $this-&gt;renderErrorMessage();\n        }\n\n        $this-&gt;context-&gt;smarty-&gt;assign(&#091;\n            &#039;quote_text&#039;   =&gt; $quote-&gt;getQuote(),\n            &#039;quote_author&#039; =&gt; $quote-&gt;getAuthor(),\n            &#039;quote_id&#039;     =&gt; $quote-&gt;getId(),\n        ]);\n\n        return $this-&gt;display(__FILE__, &#039;views\/templates\/hook\/dashboard_quote.tpl&#039;);\n    }\n\n    private function clearModuleCache(): void\n    {\n        $container = SymfonyContainer::getInstance();\n\n        if ($container-&gt;has(QuoteCacheManager::class)) {\n            \/** @var QuoteCacheManager $cacheManager *\/\n            $cacheManager = $container-&gt;get(QuoteCacheManager::class);\n            $cacheManager-&gt;clear();\n        }\n    }\n}<\/pre>\n\n\n\n<h4 class=\"wp-block-heading\">Step 8: Create the View Templates<\/h4>\n\n\n\n<p><strong>File:<\/strong>&nbsp;<code>\/modules\/wkdailyquote\/views\/templates\/hook\/dashboard_quote.tpl<\/code><\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\">&lt;section id=&quot;wkdailyquote&quot; class=&quot;panel widget wkdailyquote-container&quot;&gt;\n  &lt;div class=&quot;panel-heading&quot;&gt;\n    &lt;i class=&quot;icon-quote-left&quot;&gt;&lt;\/i&gt;\n    {l s=&#039;Quote of the Moment&#039; mod=&#039;wkdailyquote&#039;}\n  &lt;\/div&gt;\n  &lt;div class=&quot;panel-body&quot;&gt;\n    &lt;blockquote class=&quot;wkdailyquote-quote&quot;&gt;\n      &lt;p&gt;{$quote_text|escape:&#039;html&#039;:&#039;UTF-8&#039;}&lt;\/p&gt;\n      &lt;footer&gt;&lt;cite&gt;{$quote_author|escape:&#039;html&#039;:&#039;UTF-8&#039;}&lt;\/cite&gt;&lt;\/footer&gt;\n    &lt;\/blockquote&gt;\n  &lt;\/div&gt;\n&lt;\/section&gt;<\/pre>\n\n\n\n<p>In this example, we are displaying a quote on dashboard using the PrestaShop hook. <\/p>\n\n\n\n<p>While simple, this module will shows the exact architecture required for complex integrations like ERPs, shipping carriers, or payment gateways.<\/p>\n\n\n\n<p><strong>Here is the result below:<\/strong><\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img decoding=\"async\" width=\"1200\" height=\"606\" src=\"https:\/\/cdnblog.webkul.com\/blog\/wp-content\/uploads\/2026\/02\/wkdailyquote-1200x606.webp\" alt=\"wkdailyquote\" class=\"wp-image-527291\" srcset=\"https:\/\/cdnblog.webkul.com\/blog\/wp-content\/uploads\/2026\/02\/wkdailyquote-1200x606.webp 1200w, https:\/\/cdnblog.webkul.com\/blog\/wp-content\/uploads\/2026\/02\/wkdailyquote-300x151.webp 300w, https:\/\/cdnblog.webkul.com\/blog\/wp-content\/uploads\/2026\/02\/wkdailyquote-250x126.webp 250w, https:\/\/cdnblog.webkul.com\/blog\/wp-content\/uploads\/2026\/02\/wkdailyquote-768x388.webp 768w, https:\/\/cdnblog.webkul.com\/blog\/wp-content\/uploads\/2026\/02\/wkdailyquote.webp 1296w\" sizes=\"(max-width: 1200px) 100vw, 1200px\" loading=\"lazy\" \/><\/figure>\n\n\n\n<p>The architecture you&#8217;ve built is designed to scale. Here are four powerful ways to extend its capabilities once the foundation is in place:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Authentication for API Requests:<\/strong>&nbsp;Secure your connections by implementing Bearer tokens, API keys, or OAuth2 headers directly within a scoped client configuration.<\/li>\n\n\n\n<li><strong>Handling POST Requests with JSON Payloads:<\/strong>&nbsp;Move beyond simple GET requests. The client makes it easy to send data; simply use the&nbsp;<code>json<\/code>&nbsp;key in your request options to automatically encode arrays and set the&nbsp;<code>Content-Type<\/code>&nbsp;header.<\/li>\n\n\n\n<li><strong>Implementing Rate Limiting:<\/strong>&nbsp;Prevent API bans by using the Rate Limiter component. This ensures your module stays within the provider&#8217;s usage limits, even during high-traffic periods.<\/li>\n\n\n\n<li><strong>Asynchronous and Parallel Requests:<\/strong>&nbsp;Drastically improve performance when fetching data from multiple sources. The Symfony HTTP Client is non-blocking, allowing you to trigger multiple requests simultaneously and only wait when you actually need the data.<\/li>\n<\/ul>\n\n\n\n<p>That\u2019s all about this blog.<\/p>\n\n\n\n<p>If any issues or doubts, please feel free to mention them in the comment section.<\/p>\n\n\n\n<p>Or contact us at&nbsp;<a href=\"mailto:support@webkul.com\">support@webkul.com<\/a><\/p>\n\n\n\n<p>I would be happy to help.<\/p>\n\n\n\n<p>Also, you can explore our&nbsp;<a href=\"https:\/\/webkul.com\/prestashop-development\/\">PrestaShop Development Services<\/a>&nbsp;and a large range of quality&nbsp;<a href=\"https:\/\/store.webkul.com\/PrestaShop-Extensions.html\">PrestaShop Modules<\/a>.<\/p>\n\n\n\n<p><\/p>\n","protected":false},"excerpt":{"rendered":"<p>PrestaShop 9 marks a shift in architecture by officially removing Guzzle from its core dependencies. For years, Guzzle was the standard for HTTP communication in the PHP ecosystem. However, as PrestaShop moves on\u00a0to Symfony 6.4 LTS, the platform now standardizes on the native\u00a0Symfony HTTP Client. While shifting away from a familiar tool might feel disruptive <a href=\"https:\/\/webkul.com\/blog\/how-to-use-symfony-http-prestashop-9\/\">[&#8230;]<\/a><\/p>\n","protected":false},"author":741,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[209],"tags":[2065],"class_list":["post-526044","post","type-post","status-publish","format-standard","hentry","category-prestashop","tag-prestashop"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v24.5 - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>How to Use Symfony HTTP Client in PrestaShop 9 - Webkul Blog<\/title>\n<meta name=\"description\" content=\"How to migrate your PrestaShop modules to the Symfony HTTP Client. A complete blog for PrestaShop 9 developers on modern API integration and service architecture.\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/webkul.com\/blog\/how-to-use-symfony-http-prestashop-9\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"How to Use Symfony HTTP Client in PrestaShop 9 - Webkul Blog\" \/>\n<meta property=\"og:description\" content=\"How to migrate your PrestaShop modules to the Symfony HTTP Client. A complete blog for PrestaShop 9 developers on modern API integration and service architecture.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/webkul.com\/blog\/how-to-use-symfony-http-prestashop-9\/\" \/>\n<meta property=\"og:site_name\" content=\"Webkul Blog\" \/>\n<meta property=\"article:publisher\" content=\"https:\/\/www.facebook.com\/webkul\/\" \/>\n<meta property=\"article:published_time\" content=\"2026-02-27T13:35:53+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2026-02-27T13:36:01+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/webkul.com\/blog\/wp-content\/uploads\/2026\/02\/servicearchitectureflow.webp\" \/>\n<meta name=\"author\" content=\"Akash Singh\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:creator\" content=\"@webkul\" \/>\n<meta name=\"twitter:site\" content=\"@webkul\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Akash Singh\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"4 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\/\/webkul.com\/blog\/how-to-use-symfony-http-prestashop-9\/#article\",\"isPartOf\":{\"@id\":\"https:\/\/webkul.com\/blog\/how-to-use-symfony-http-prestashop-9\/\"},\"author\":{\"name\":\"Akash Singh\",\"@id\":\"https:\/\/webkul.com\/blog\/#\/schema\/person\/0b2dcd00c41425515f45478eef695a27\"},\"headline\":\"How to Use Symfony HTTP Client in PrestaShop 9\",\"datePublished\":\"2026-02-27T13:35:53+00:00\",\"dateModified\":\"2026-02-27T13:36:01+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/webkul.com\/blog\/how-to-use-symfony-http-prestashop-9\/\"},\"wordCount\":799,\"commentCount\":0,\"publisher\":{\"@id\":\"https:\/\/webkul.com\/blog\/#organization\"},\"image\":{\"@id\":\"https:\/\/webkul.com\/blog\/how-to-use-symfony-http-prestashop-9\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/webkul.com\/blog\/wp-content\/uploads\/2026\/02\/servicearchitectureflow.webp\",\"keywords\":[\"prestashop\"],\"articleSection\":[\"prestashop\"],\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\/\/webkul.com\/blog\/how-to-use-symfony-http-prestashop-9\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/webkul.com\/blog\/how-to-use-symfony-http-prestashop-9\/\",\"url\":\"https:\/\/webkul.com\/blog\/how-to-use-symfony-http-prestashop-9\/\",\"name\":\"How to Use Symfony HTTP Client in PrestaShop 9 - Webkul Blog\",\"isPartOf\":{\"@id\":\"https:\/\/webkul.com\/blog\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/webkul.com\/blog\/how-to-use-symfony-http-prestashop-9\/#primaryimage\"},\"image\":{\"@id\":\"https:\/\/webkul.com\/blog\/how-to-use-symfony-http-prestashop-9\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/webkul.com\/blog\/wp-content\/uploads\/2026\/02\/servicearchitectureflow.webp\",\"datePublished\":\"2026-02-27T13:35:53+00:00\",\"dateModified\":\"2026-02-27T13:36:01+00:00\",\"description\":\"How to migrate your PrestaShop modules to the Symfony HTTP Client. A complete blog for PrestaShop 9 developers on modern API integration and service architecture.\",\"breadcrumb\":{\"@id\":\"https:\/\/webkul.com\/blog\/how-to-use-symfony-http-prestashop-9\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/webkul.com\/blog\/how-to-use-symfony-http-prestashop-9\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/webkul.com\/blog\/how-to-use-symfony-http-prestashop-9\/#primaryimage\",\"url\":\"https:\/\/cdnblog.webkul.com\/blog\/wp-content\/uploads\/2026\/02\/servicearchitectureflow.webp\",\"contentUrl\":\"https:\/\/cdnblog.webkul.com\/blog\/wp-content\/uploads\/2026\/02\/servicearchitectureflow.webp\",\"width\":880,\"height\":196,\"caption\":\"servicearchitectureflow\"},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/webkul.com\/blog\/how-to-use-symfony-http-prestashop-9\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/webkul.com\/blog\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"How to Use Symfony HTTP Client in PrestaShop 9\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/webkul.com\/blog\/#website\",\"url\":\"https:\/\/webkul.com\/blog\/\",\"name\":\"Webkul Blog\",\"description\":\"\",\"publisher\":{\"@id\":\"https:\/\/webkul.com\/blog\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/webkul.com\/blog\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Organization\",\"@id\":\"https:\/\/webkul.com\/blog\/#organization\",\"name\":\"WebKul Software Private Limited\",\"url\":\"https:\/\/webkul.com\/blog\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/webkul.com\/blog\/#\/schema\/logo\/image\/\",\"url\":\"https:\/\/cdnblog.webkul.com\/blog\/wp-content\/uploads\/2021\/08\/webkul-logo-accent-sq.png\",\"contentUrl\":\"https:\/\/cdnblog.webkul.com\/blog\/wp-content\/uploads\/2021\/08\/webkul-logo-accent-sq.png\",\"width\":380,\"height\":380,\"caption\":\"WebKul Software Private Limited\"},\"image\":{\"@id\":\"https:\/\/webkul.com\/blog\/#\/schema\/logo\/image\/\"},\"sameAs\":[\"https:\/\/www.facebook.com\/webkul\/\",\"https:\/\/x.com\/webkul\",\"https:\/\/www.instagram.com\/webkul\/\",\"https:\/\/www.linkedin.com\/company\/webkul\",\"https:\/\/www.youtube.com\/user\/webkul\/\"]},{\"@type\":\"Person\",\"@id\":\"https:\/\/webkul.com\/blog\/#\/schema\/person\/0b2dcd00c41425515f45478eef695a27\",\"name\":\"Akash Singh\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/webkul.com\/blog\/#\/schema\/person\/image\/\",\"url\":\"https:\/\/secure.gravatar.com\/avatar\/7097d120782f09dd35e229eaad21029c99d5e03659a10f4201610ec7e8c2232a?s=96&d=https%3A%2F%2Fcdnblog.webkul.com%2Fblog%2Fwp-content%2Fuploads%2F2019%2F10%2Fmike.png&r=g\",\"contentUrl\":\"https:\/\/secure.gravatar.com\/avatar\/7097d120782f09dd35e229eaad21029c99d5e03659a10f4201610ec7e8c2232a?s=96&d=https%3A%2F%2Fcdnblog.webkul.com%2Fblog%2Fwp-content%2Fuploads%2F2019%2F10%2Fmike.png&r=g\",\"caption\":\"Akash Singh\"},\"url\":\"https:\/\/webkul.com\/blog\/author\/akashsingh-presta435\/\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"How to Use Symfony HTTP Client in PrestaShop 9 - Webkul Blog","description":"How to migrate your PrestaShop modules to the Symfony HTTP Client. A complete blog for PrestaShop 9 developers on modern API integration and service architecture.","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/webkul.com\/blog\/how-to-use-symfony-http-prestashop-9\/","og_locale":"en_US","og_type":"article","og_title":"How to Use Symfony HTTP Client in PrestaShop 9 - Webkul Blog","og_description":"How to migrate your PrestaShop modules to the Symfony HTTP Client. A complete blog for PrestaShop 9 developers on modern API integration and service architecture.","og_url":"https:\/\/webkul.com\/blog\/how-to-use-symfony-http-prestashop-9\/","og_site_name":"Webkul Blog","article_publisher":"https:\/\/www.facebook.com\/webkul\/","article_published_time":"2026-02-27T13:35:53+00:00","article_modified_time":"2026-02-27T13:36:01+00:00","og_image":[{"url":"https:\/\/webkul.com\/blog\/wp-content\/uploads\/2026\/02\/servicearchitectureflow.webp","type":"","width":"","height":""}],"author":"Akash Singh","twitter_card":"summary_large_image","twitter_creator":"@webkul","twitter_site":"@webkul","twitter_misc":{"Written by":"Akash Singh","Est. reading time":"4 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/webkul.com\/blog\/how-to-use-symfony-http-prestashop-9\/#article","isPartOf":{"@id":"https:\/\/webkul.com\/blog\/how-to-use-symfony-http-prestashop-9\/"},"author":{"name":"Akash Singh","@id":"https:\/\/webkul.com\/blog\/#\/schema\/person\/0b2dcd00c41425515f45478eef695a27"},"headline":"How to Use Symfony HTTP Client in PrestaShop 9","datePublished":"2026-02-27T13:35:53+00:00","dateModified":"2026-02-27T13:36:01+00:00","mainEntityOfPage":{"@id":"https:\/\/webkul.com\/blog\/how-to-use-symfony-http-prestashop-9\/"},"wordCount":799,"commentCount":0,"publisher":{"@id":"https:\/\/webkul.com\/blog\/#organization"},"image":{"@id":"https:\/\/webkul.com\/blog\/how-to-use-symfony-http-prestashop-9\/#primaryimage"},"thumbnailUrl":"https:\/\/webkul.com\/blog\/wp-content\/uploads\/2026\/02\/servicearchitectureflow.webp","keywords":["prestashop"],"articleSection":["prestashop"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/webkul.com\/blog\/how-to-use-symfony-http-prestashop-9\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/webkul.com\/blog\/how-to-use-symfony-http-prestashop-9\/","url":"https:\/\/webkul.com\/blog\/how-to-use-symfony-http-prestashop-9\/","name":"How to Use Symfony HTTP Client in PrestaShop 9 - Webkul Blog","isPartOf":{"@id":"https:\/\/webkul.com\/blog\/#website"},"primaryImageOfPage":{"@id":"https:\/\/webkul.com\/blog\/how-to-use-symfony-http-prestashop-9\/#primaryimage"},"image":{"@id":"https:\/\/webkul.com\/blog\/how-to-use-symfony-http-prestashop-9\/#primaryimage"},"thumbnailUrl":"https:\/\/webkul.com\/blog\/wp-content\/uploads\/2026\/02\/servicearchitectureflow.webp","datePublished":"2026-02-27T13:35:53+00:00","dateModified":"2026-02-27T13:36:01+00:00","description":"How to migrate your PrestaShop modules to the Symfony HTTP Client. A complete blog for PrestaShop 9 developers on modern API integration and service architecture.","breadcrumb":{"@id":"https:\/\/webkul.com\/blog\/how-to-use-symfony-http-prestashop-9\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/webkul.com\/blog\/how-to-use-symfony-http-prestashop-9\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/webkul.com\/blog\/how-to-use-symfony-http-prestashop-9\/#primaryimage","url":"https:\/\/cdnblog.webkul.com\/blog\/wp-content\/uploads\/2026\/02\/servicearchitectureflow.webp","contentUrl":"https:\/\/cdnblog.webkul.com\/blog\/wp-content\/uploads\/2026\/02\/servicearchitectureflow.webp","width":880,"height":196,"caption":"servicearchitectureflow"},{"@type":"BreadcrumbList","@id":"https:\/\/webkul.com\/blog\/how-to-use-symfony-http-prestashop-9\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/webkul.com\/blog\/"},{"@type":"ListItem","position":2,"name":"How to Use Symfony HTTP Client in PrestaShop 9"}]},{"@type":"WebSite","@id":"https:\/\/webkul.com\/blog\/#website","url":"https:\/\/webkul.com\/blog\/","name":"Webkul Blog","description":"","publisher":{"@id":"https:\/\/webkul.com\/blog\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/webkul.com\/blog\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Organization","@id":"https:\/\/webkul.com\/blog\/#organization","name":"WebKul Software Private Limited","url":"https:\/\/webkul.com\/blog\/","logo":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/webkul.com\/blog\/#\/schema\/logo\/image\/","url":"https:\/\/cdnblog.webkul.com\/blog\/wp-content\/uploads\/2021\/08\/webkul-logo-accent-sq.png","contentUrl":"https:\/\/cdnblog.webkul.com\/blog\/wp-content\/uploads\/2021\/08\/webkul-logo-accent-sq.png","width":380,"height":380,"caption":"WebKul Software Private Limited"},"image":{"@id":"https:\/\/webkul.com\/blog\/#\/schema\/logo\/image\/"},"sameAs":["https:\/\/www.facebook.com\/webkul\/","https:\/\/x.com\/webkul","https:\/\/www.instagram.com\/webkul\/","https:\/\/www.linkedin.com\/company\/webkul","https:\/\/www.youtube.com\/user\/webkul\/"]},{"@type":"Person","@id":"https:\/\/webkul.com\/blog\/#\/schema\/person\/0b2dcd00c41425515f45478eef695a27","name":"Akash Singh","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/webkul.com\/blog\/#\/schema\/person\/image\/","url":"https:\/\/secure.gravatar.com\/avatar\/7097d120782f09dd35e229eaad21029c99d5e03659a10f4201610ec7e8c2232a?s=96&d=https%3A%2F%2Fcdnblog.webkul.com%2Fblog%2Fwp-content%2Fuploads%2F2019%2F10%2Fmike.png&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/7097d120782f09dd35e229eaad21029c99d5e03659a10f4201610ec7e8c2232a?s=96&d=https%3A%2F%2Fcdnblog.webkul.com%2Fblog%2Fwp-content%2Fuploads%2F2019%2F10%2Fmike.png&r=g","caption":"Akash Singh"},"url":"https:\/\/webkul.com\/blog\/author\/akashsingh-presta435\/"}]}},"amp_enabled":true,"_links":{"self":[{"href":"https:\/\/webkul.com\/blog\/wp-json\/wp\/v2\/posts\/526044","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/webkul.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/webkul.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/webkul.com\/blog\/wp-json\/wp\/v2\/users\/741"}],"replies":[{"embeddable":true,"href":"https:\/\/webkul.com\/blog\/wp-json\/wp\/v2\/comments?post=526044"}],"version-history":[{"count":47,"href":"https:\/\/webkul.com\/blog\/wp-json\/wp\/v2\/posts\/526044\/revisions"}],"predecessor-version":[{"id":528679,"href":"https:\/\/webkul.com\/blog\/wp-json\/wp\/v2\/posts\/526044\/revisions\/528679"}],"wp:attachment":[{"href":"https:\/\/webkul.com\/blog\/wp-json\/wp\/v2\/media?parent=526044"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/webkul.com\/blog\/wp-json\/wp\/v2\/categories?post=526044"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/webkul.com\/blog\/wp-json\/wp\/v2\/tags?post=526044"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}