Skip to content
Advertisement

Use a request header with HTTP Client to external Api server

Consider the following request to a Symfony controller:

http http://127.0.0.1:8000/index x-token:1000
#[Route('/index', name: 'index')]
public function index(HttpClientInterface $client, Request $request): Response
{
    $client->request('GET', 'http://0.0.0.0:3001', ['headers' => ['x-token' => $request->headers->get('x-token')]]);
    return new JsonResponse();
}

This code snippet is a minimal example for the usage in a controller. The controller accepts a Request, and uses the x-token header for authenticating against the 3rd Party Api (here: localhost:3001).

Is there a way, to automate this process? So basically – listen to incoming requests and inject the x-token header into a specific Scoped Client or the default client in Symfony.

The goal is, not to do this in every usage of the Http Client, but have a configured client service.

The client will be used all over the codebase, not just in a controller like in this minimal example.

I know that I can use Service Decoration and extend the clients in use. I fail how to connect the dots and make this work.

Advertisement

Answer

Have you tried using symfony kernel events?

First of all, if you are calling some 3rd-party api, I’d suggest you to create a separate class at the infrastructure layer, for example MyApiProvider. Using HttpClient right from your controller is not smart, because you may also want to adjust something (for example api host, etc). So it’s gonna look like this:

<?php

namespace AppInfrastructureProvider;

class MyApiProvider
{
    // Of course, this also be better configurable via your .env file
    private const HOST = 'http://0.0.0.0:3001';

    private HttpClientInterface $client;

    private ?string $token = null;

    public function __construct(HttpClientInterface $client)
    {
        $this->client = $client;
    }

    public function setToken(string $token): void
    {
        $this->token = $token;
    }


    public function getSomething(): array
    {
        $response = $this->client->request(
            'GET',
            self::HOST,
            ['headers' => $this->getHeaders()]
        );

        return $response->toArray();
    }

    private function getHeaders(): array
    {
        $headers = [];
        if ($this->token !== null) {
            $headers['x-token'] = $this->token;
        }

        return $headers;
    }
}

Then you need to use symfony’s kernel.request event to inject token to your provider from the request:

<?php

namespace AppEvent;

use SymfonyComponentHttpKernelEventKernelEvent;

class RequestTokenEventListener
{
    private MyApiProvider $provider;

    public function __construct(MyApiProvider $provider)
    {
        $this->provider = $provider;
    }

    public function onKernelController(KernelEvent $event): void
    {
        $request = $event->getRequest();
        $token = $request->headers->get('x-token');

        if ($token !== null) {
            $this->provider->setToken($token);
        }
    }
}

And finally your controller:

#[Route('/index', name: 'index')]
public function index(MyApiProvider $provider): Response
{
    $provider->getSomething();

    return new JsonResponse();
}

So your provider is gonna have token context during each request, if the token is passed.

User contributions licensed under: CC BY-SA
4 People found this is helpful
Advertisement