---
title: "HTTP requests to external sources"
manual: "TYPO3 Explained"
version: "11.5"
permalink: "https://docs.typo3.org/permalink/t3coreapi:http@11.5"
source: "ExtensionArchitecture/HowTo/RestRequests/Index.rst"
rendered: "2026-10-21T15:30:00+00:00"
---

> [!WARNING]
> **Attention**
>
> TYPO3 v11 has reached end-of-life as of October 31th 2024 and
> is no longer being maintained. Use the version switcher on the top
> left of this page to select documentation for a supported version of TYPO3.
>
> Need more time before upgrading?
> You can purchase Extended Long Term Support (ELTS) for TYPO3 v11 here:
> [TYPO3 ELTS](https://typo3.com/services/extended-support-elts).

# HTTP requests to external sources {#http}

The PHP library "Guzzle" is available in TYPO3 as a feature-rich solution for
creating HTTP requests based on the PSR-7 interfaces.

Guzzle automatically detects the underlying adapters available on the system,
such as cURL or stream wrappers, and chooses the best solution for the system.

A TYPO3-specific PHP class named `\TYPO3\CMS\Core\Http\RequestFactory` is
present as a simplified wrapper for accessing Guzzle clients.

All options available under `$GLOBALS['TYPO3_CONF_VARS']['HTTP']` are
automatically applied to the Guzzle clients when using the `RequestFactory`
class. The options are a subset of the available options from Guzzle, but can be
extended.

> [!NOTE]
> **See also**
>
> -   [HTTP - tune requests](https://docs.typo3.org/permalink/t3coreapi:typo3confvars-http@11.5)
> -   [Guzzle request options](https://docs.guzzlephp.org/en/stable/request-options.html)
> -   [Full documentation for Guzzle](https://docs.guzzlephp.org/en/stable/)

Although Guzzle can handle Promises/A+ and asynchronous requests, it currently
serves as a drop-in replacement for the previous mixed options and
implementations within `GeneralUtility::getUrl()` and a PSR-7-based API for
HTTP requests.

The TYPO3-specific wrapper `GeneralUtility::getUrl()` uses Guzzle for
remote files, eliminating the need to directly configure settings based on
specific implementations such as stream wrappers or cURL.

## Basic usage {#http-basic}

The `RequestFactory` class can be used like this (PHP 8.1-compatible code):

**EXT:examples/Classes/Http/MeowInformationRequester.php**

```php
<?php

declare(strict_types=1);

namespace T3docs\Examples\Http;

use TYPO3\CMS\Core\Http\RequestFactory;

final class MeowInformationRequester
{
    private const API_URL = 'https://catfact.ninja/fact';

    // We need the RequestFactory for creating and sending a request,
    // so we inject it into the class using constructor injection.
    public function __construct(
        private readonly RequestFactory $requestFactory,
    ) {
    }

    public function request(): string
    {
        // Additional headers for this specific request
        // See: https://docs.guzzlephp.org/en/stable/request-options.html
        $additionalOptions = [
            'headers' => ['Cache-Control' => 'no-cache'],
            'allow_redirects' => false,
        ];

        // Get a PSR-7-compliant response object
        $response = $this->requestFactory->request(
            self::API_URL,
            'GET',
            $additionalOptions
        );

        if ($response->getStatusCode() !== 200) {
            throw new \RuntimeException(
                'Returned status code is ' . $response->getStatusCode()
            );
        }

        if ($response->getHeaderLine('Content-Type') !== 'application/json') {
            throw new \RuntimeException(
                'The request did not return JSON data'
            );
        }

        // Get the content as a string on a successful request
        return json_decode($response->getBody()->getContents(), true)['fact']
            ?? throw new \RuntimeException('No information available');
    }
}
```

A POST request can be achieved with:

**EXT:my_extension/Classes/SomeClass.php**

```php
$additionalOptions = [
    'body' => 'Your raw post data',
    // OR form data:
    'form_params' => [
        'first_name' => 'Jane',
        'last_name' => 'Doe',
    ]
];

$response = $this->requestFactory->request($url, 'POST', $additionalOptions);
```

Extension authors are advised to use the `RequestFactory` class instead of
using the Guzzle API directly in order to ensure a clear upgrade path when
updates to the underlying API need to be done.

## Custom middleware handlers {#http-custom-handlers}

Guzzle accepts a stack of custom middleware handlers which can be configured
in `$GLOBALS['TYPO3_CONF_VARS']['HTTP']['handler']` as an array. If a
custom configuration is specified, the default handler stack will be extended
and not overwritten.

**typo3conf/AdditionalConfiguration.php**

```php
// Add custom middlewares to default Guzzle handler stack
$GLOBALS['TYPO3_CONF_VARS']['HTTP']['handler'][] =
    (\TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance(
        \MyVendor\MyExtension\Middleware\Guzzle\CustomMiddleware::class
    ))->handler();
$GLOBALS['TYPO3_CONF_VARS']['HTTP']['handler'][] =
    (\TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance(
        \MyVendor\MyExtension\Middleware\Guzzle\SecondCustomMiddleware::class
    ))->handler();
```

## HTTP Utility Methods {#http-utility-methods}

TYPO3 provides a small set of helper methods related to HTTP Requests in the class `HttpUtility`:

### HttpUtility::redirect {#httputility-redirect}

<!-- TODO: no Markdown rendering for "deprecated" -->

This method is deprecated and will be removed with TYPO3 v12.0. Create a
direct response using the ResponseFactory
instead.

#### Migration {#http-utility-response-migration}

Most of the time, a proper PSR-7 response can be returned to the call stack
(request handler). Unfortunately there might still be some places within the
call stack where it is not possible to return a PSR-7 response directly. In such
a case a `\TYPO3\CMS\Core\Http\PropagateResponseException` could be thrown.
This is automatically caught by a PSR-15 middleware and the given PSR-7 response
is then returned directly.

```php
// Before
HttpUtility::redirect('https://example.org/', HttpUtility::HTTP_STATUS_303);

// After

// use Psr\Http\Message\ResponseFactoryInterface
// use TYPO3\CMS\Core\Http\PropagateResponseException

// Inject PSR-17 ResponseFactoryInterface
public function __construct(ResponseFactoryInterface $responseFactory)
{
    $this->responseFactory = $responseFactory
}

// Create redirect response
$response = $this->responseFactory
    ->createResponse(303)
    ->withAddedHeader('location', 'https://example.org/')

// Return response directly
return $response;

// Or throw PropagateResponseException
new PropagateResponseException($response);
```

> [!NOTE]
> Throwing exceptions for returning an immediate PSR-7 response is only
> considered as an intermediate solution until it is possible to return PSR-7
> responses at any relevant place. Therefore, the exception is marked as
> `@internal` and will most likely vanish in the future.

### HttpUtility::setResponseCode {#httputility-setresponsecode}

<!-- TODO: no Markdown rendering for "deprecated" -->

This method is deprecated and will be removed with TYPO3 v12.0. Create a
direct response using the ResponseFactory
instead. See also Migration.

### HttpUtility::setResponseCodeAndExit {#httputility-setresponsecodeandexit}

<!-- TODO: no Markdown rendering for "deprecated" -->

This method is deprecated and will be removed with TYPO3 v12.0. Create a
direct response using the ResponseFactory
instead. See also Migration.

### HttpUtility::buildUrl {#httputility-buildurl}

Creates a URL string from an array containing the URL parts, such as those
output by `parse_url()`.

### HttpUtility::buildQueryString {#httputility-buildquerystring}

The `buildQueryString()` method is an enhancement to the [PHP function](https://www.php.net/manual/en/function.http-build-query.php)
`http_build_query()`. It implodes multidimensional parameter arrays and
properly encodes parameter names as well as values into a valid query string
with an optional prepend of `?` or `&`.

If the query is not empty, `?` or `&` are prepended in the correct sequence.
Empty parameters are skipped.
