for my app i want to separate the api from two different frontends. The api routes themselves return a json response and i want to call api methods directly from the frontend routes.
$app->get('/language[/{id:[0-9]+}]', function ($request, $response, $args) use ($app) {
// Make a subrequest to the api method
$res = $app->subRequest('GET', 'api/language', (!isset($args['id'])) ? '' : $args['id']);
$json = $res->getBody();
$language = json_decode($json, true);
// Sample log message
$this->logger->info("Slim-Skeleton '/' route");
// Render index view
return $this->renderer->render($response, 'index.phtml', ['lang' => $language]);
})->setName('get-api-language');
The problem is that when i call the $app->subrequest method the render renders the subrequest response first and then outputs the index.phtml template populated with the decoded json data.
There is in slim a better method to not outputdirectly the subrequest response into the main application request?
<?php
namespace App\Actions\Language;
use Psr\Http\Message\ServerRequestInterface as Request;
use Psr\Http\Message\ResponseInterface as Response;
use App\DataMappers\Language\LanguageMapper;
class GetLanguage {
protected $db;
public function __construct($container) {
$this->db = $container->get('db');
}
public function __invoke(Request $request, Response $response, $args) {
$mapper = new LanguageMapper($this->db);
if (isset($args['id'])) {
$res = $mapper->findById($args['id']);
if (empty($res)) {
return $response->withStatus(404)
->withHeader('Content-Type', 'text/html')
->write('Page not found');
}
} else {
$res = $mapper->findAll();
}
return json_encode($res);
}
}
The language mapper object makes sample query to database via PDO and returns a JsonSerializable container class, there are not echo in all the api.
forgot to say that I’m on latest slim3.
UPDATE:
If i var_dump($reponse) inside the main route the result is null like this:
$app->get('/language[/{id:[0-9]+}]', function ($request, $response, $args) use ($app) {
// Make a subrequest to the api method
$res = $app->subRequest('GET', 'api/language', (!isset($args['id'])) ? '' : $args['id']);
$json = $res->getBody();
$language = json_decode($json, true);
// Sample log message
$this->logger->info("Slim-Skeleton '/' route");
// resulting response is null
var_dump($reponse);
// Render index view
return $this->renderer->render($response, 'index.phtml', ['lang' => $language]);
})->setName('get-api-language');
So you are right the subrequest outputs nothing, but $this->renderer->render method seems that catch the subRequest response
$response->getBody()->write(json_encode($res));
// also set content type if you are not doing so elsewhere
$response = $response->withHeader('Content-Type', 'application/json;charset=utf-8')
return $response; // important to return the response object
// or Slim specific:
return $response->withJson($res);
Ohw I see, that is what’s happening. It seems subRequest uses the request from the container, which is the same one the app itself uses (conainer returns the same instance of response if pulled twice). This architecture is something that bugged Slim before and there are plans to remove the request and response object from the container as they do not belong there.
I think passing a new response instance into the subRequest will also do the job.
Well, if you look at the signature of the subRequest method you see that the last parameter is a response object. So just create a new instance ResponseInterface and pass it it.
Also it you do not pass a response instance at all it will create a new instance for you.
My reason for asking on this is same as acidvertigo’s, when I do $response->withJson($data), the JSON is displayed since I’m returning the response from the front-end. I need the response from the /api/v1/login endpoint to be a different response than the /login front-end route’s.
Looking at those links, I don’t see any discussion on why this is going away or what(if anything) it is being replaced with. Any idea on why its going away or if its being replaced with something?
We are removing subRequest as it does not fit well with proper code design.
In instances where one might need a “sub” request, it is almost always the wrong design choice to resend an HTTP Request through Slim again. Typically we remove features that are not considered good practice with every Major release [ Slim 2 => 3 we removed service location … as an example ].