How to call another internal endpoint from within zend expressive REST api application?

570 Views Asked by At

I am trying to call an REST api endpoint(internal) from within another method in zend expressive (PSR-7) application. Currently what I'm doing is, I send another http request like this (docs):

$request = (new Zend\Diactoros\Request())
    ->withUri(new Zend\Diactoros\Uri('http://example.com'))
    ->withMethod('PATCH')
    ->withAddedHeader('Authorization', 'Bearer ' . $token)
    ->withAddedHeader('Content-Type', 'application/json');

$request->getBody()->write(json_encode($data));
$response = $client->send($request);

But I was wondering since I'm trying to call an internal endpoint, would I be able to forward the request somehow? I've heard of controller plugin forwards, but I'm not sure how that works.

Endpoint url and request type is retrieved from a database. I can call the method directly, but forwarding the endpoint would reduce the work that's required to conditionally check for each modules.

Appreciate if you could point me in the right direction.

Update:

Let me explain the use case. We have a scheduler database which contains endpoints and params to send. A cURL request is sent to the scheduler API every 5 minutes (CRON). Scheduler checks for the interval provided in the db and triggers respective endpoints at this interval.

2

There are 2 best solutions below

0
On

The first method that comes into my mind would be to convert the current class (probably an implementation of RequestHandleInterface) into a middleware (MiddlewareInterface) and change the route definition. Instead of RequestHandler::class you would have [Middleware::class, RequestHandler::class] (e.g. [EditEntityMiddleware::class, GetEntityHandler::class]). If you need to pass information from the middleware to the handler you simply add it to the request:

return $handler->handle($request->withAttribute('newInfo' => $newInfo));

In order to access the information in the request handler:

$newInfo = $request->getAttribute('newInfo');

This API should respond much faster, but if you have a lot of endpoints it might be difficult to add/edit a lot of routes.

If you give us a more concludent example we might come with better answers. I encountered the same situation when editing an entity as I had to make the change into the database and return the new entity. For the EditHandler I just extended the GetEntityHandler ("handle" method). I first updated the database entity and then simply called return parent::handle($request) which returns the new database entity.

0
On

So if I understand correctly your API receives a set of commands and a set of parameters for each command. I would create a separate class for each command, and a class that contains the mapping, you might see it as a factory.

API:

public function handle(ServerRequestInterface $request): ResponseInterface
{
    $parameters = $request->getAttribute('parameters');
    foreach($request->getAttribute('commands') as $commandName){
        $commandClass = CommandsMappingClass::getClassForCommand($commandName);

        //you can save the response if you need to
        (new $commandClass())->__invoke($parameters[$commandName]);
    }


}

CommandsMappingClass:

    private const MAPPING = [
        'command1' => Command1::class,
    ];

    public static function getClassForCommand(string $commandName): ?string
    {
       //you can return a default command if you need to 
        return self::MAPPING[$commandName] ?? null;
    }

This is a rudimentary solution. The mapping can be seen as a dynamic registry, and each module of your application could add a cron job command to it (of course, the commands will not be stored in a constant). See https://docs.zendframework.com/zend-servicemanager/delegators/