Home > OS >  Use a request header with HTTP Client to external Api server
Use a request header with HTTP Client to external Api server

Time:12-15

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.

CodePudding user response:

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 App\Infrastructure\Provider;

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 App\Event;

use Symfony\Component\HttpKernel\Event\KernelEvent;

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.

  • Related