Apitte – Middlewares – logování request a repsponse

- Croc
- Člen | 270
Zdravím,
mám takový problém. Vytvářím nové REST API pomocí Apitte
s použitím Contributte\Middlewares.
Jen poznámka, middleware používám pouze pro toto API. V aplikaci ne.
Middleware mám pro authentizaci pomocí apiKey a chci ho také použít pro
logování každého requestu a response.
Pro logování requestů mi funguje, ale mám problém s logováním
response.
config.neon
middlewares:
middlewares:
- Contributte\Middlewares\TracyMiddleware
- Contributte\Middlewares\AutoBasePathMiddleware
- Apitte\Middlewares\ApiMiddleware
- App\Middlewares\ApiKeyAuthenticationMiddleware
- App\Middlewares\LogApiRequestMiddleware
- App\Middlewares\LogApiResponseMiddleware
Aktuální stav:
- Provolání API
- ApiKeyAuthenticationMiddleware
- LogApiRequestMiddleware
- LogApiResponseMiddleware
- zpracování požadavku
- vrácení odpovědi
Požadovaný stav:
- Provolání API
- ApiKeyAuthenticationMiddleware
- LogApiRequestMiddleware
- zpracování požadavku
- LogApiResponseMiddleware
- vrácení odpovědi
Problém je, že nevím jak nadefinovat
LogApiResponseMiddleware, aby se volal pouze pro response. Je to
vůbec možné? Nejsem si jistý, jestli jsem funci Middleware pochopil
správně, ale podle obrázku v dokumentaci
Contributte\Middlewares by to mělo jít.
Případně jaká je jiná alternativa? Cílem je, aby se logování provádělo automaticky pro všechny API requesty a response.

- Croc
- Člen | 270
REST API controller
<?php
namespace App\ApiRest\V1\Controllers;
use Apitte\Core\Annotation\Controller\ControllerPath;
use Apitte\Core\Annotation\Controller\Method;
use Apitte\Core\Annotation\Controller\Path;
use Apitte\Core\Annotation\Controller\RequestParameter;
use Apitte\Core\Annotation\Controller\RequestParameters;
use Apitte\Core\Annotation\Controller\Negotiations;
use Apitte\Core\Annotation\Controller\Negotiation;
use Apitte\Negotiation\SuffixNegotiator;
use Apitte\Negotiation\DefaultNegotiator;
use Apitte\Core\Annotation\Controller\Responses;
use Apitte\Core\Annotation\Controller\Response;
use Apitte\Core\Annotation\Controller\Tag;
use Apitte\Core\Http\ApiRequest;
use Apitte\Core\Http\ApiResponse;
use Apitte\Negotiation\Http\ArrayEntity;
use Apitte\OpenApi\ISchemaBuilder;
use App\Exception\LookupNotFoundOrEmptyException;
use App\Model\ApiModel;
use App\Services\LookupService;
use Log\LogService;
use Psr\Http\Message\ServerRequestInterface;
/**
* Class LookupController
* @package App\ApiRest\V1\Controllers
*
* @ControllerPath("/lookup")
* @Tag(name="Lookup")
*/
class LookupController extends BaseV1Controller
{
/**
* @var ISchemaBuilder
*/
private $schemaBuilder;
/**
* @var LookupService
*/
private $lookupService;
/**
* @var LogService
*/
private $logService;
/**
* @var ApiModel
*/
private $apiManager;
/* ----------------- */
/**
* LookupController constructor.
* @param ISchemaBuilder $schemaBuilder
* @param LookupService $lookupService
* @param LogService $logService
* @param ApiModel $apiManager
*/
public function __construct(ISchemaBuilder $schemaBuilder, LookupService $lookupService, LogService $logService, ApiModel $apiManager)
{
$this->schemaBuilder = $schemaBuilder;
$this->lookupService = $lookupService;
$this->logService = $logService;
$this->apiManager = $apiManager;
}
/**
* @param ApiRequest $request
* @param ApiResponse $response
* @return ApiResponse
*
* @Path("/{lookup}")
* @Method("GET")
* @RequestParameters({
* @RequestParameter(name="lookup", type="string", in="path", required=true, description="Name of lookup."),
* @RequestParameter(name="enabled-only", type="bool", in="query", required=false, description="Get only enabled values from lookup."),
* @RequestParameter(name="language", type="string", in="header", required=false, description="Language for description lookup values.")
* }),
* @Negotiations({
* @Negotiation(default = true, suffix = "json"),
* @Negotiation(default = false, suffix = "xml")
* }),
* @Responses({
* @Response(code="200", description="Success"),
* @Response(code="404", description="Not found")
* })
*
*/
public function lookup(ApiRequest $request, ApiResponse $response): ApiResponse
{
$params = $request->getParameters();
$lookup = $params['lookup'];
if (strpos(mb_strtolower($lookup), 'lookup') === false) {
return $response
->withStatus(ApiResponse::S404_NOT_FOUND)
->withEntity(ArrayEntity::from(['Lookup not found']));
}
try {
$data = $this->lookupService->getLookup($lookup)->getItems();
} catch (LookupNotFoundOrEmptyException $exception) {
return $response
->withStatus(ApiResponse::S404_NOT_FOUND)
->withEntity(ArrayEntity::from(['Lookup not found']));
} catch (\Exception $exception) {
$this->logService->saveExceptionToFile($exception);
return $response
->withStatus(ApiResponse::S500_INTERNAL_SERVER_ERROR)
->withEntity(ArrayEntity::from(['Unknown server error']));
}
return $response
->withStatus(ApiResponse::S200_OK)
->withEntity(ArrayEntity::from($data));
}
}
Middleware pro logování request
<?php declare(strict_types = 1);
namespace App\Middlewares;
use Apitte\Core\Http\ApiRequest;
use Apitte\Core\Http\ApiResponse;
use App\Model\ApiModel;
use App\Model\NoUserException;
use App\Services\LookupService;
use Contributte\Middlewares\IMiddleware;
use Log\LogService;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use stdClass;
/**
* Class LogApiRequestMiddleware
* @package App\Middlewares
*/
final class LogApiRequestMiddleware implements IMiddleware
{
/**
* @var ApiModel
*/
private $apiModel;
/**
* @var LogService
*/
private $logService;
/**
* ApiKeyAuthenticationMiddleware constructor.
* @param ApiModel $apiModel
* @param LogService $logService
*/
public function __construct(ApiModel $apiModel, LogService $logService)
{
$this->apiModel = $apiModel;
$this->logService = $logService;
}
/**
* @param ServerRequestInterface $request
* @param ResponseInterface $response
* @param callable $next
* @return ResponseInterface
* @throws \App\Repository\TransactionFailException
* @throws \Dibi\DriverException
* @throws \Dibi\Exception
*/
public function __invoke(ServerRequestInterface $request, ResponseInterface $response, callable $next): ResponseInterface
{
if ($request->getUri()->getPath() === '/api-rest/v1/') {
return $next($request, $response);
}
$id = $this->apiModel->logRestApiRequest($request);
return $next($request->withAttribute('id_request', $id), $response);
}
}
Middleware pro logování response
<?php declare(strict_types = 1);
namespace App\Middlewares;
use Apitte\Core\Http\ApiRequest;
use Apitte\Core\Http\ApiResponse;
use App\Model\ApiModel;
use Contributte\Middlewares\IMiddleware;
use Log\LogService;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
/**
* Class LogApiResponseMiddleware
* @package App\Middlewares
*/
final class LogApiResponseMiddleware implements IMiddleware
{
/**
* @var ApiModel
*/
private $apiModel;
/**
* @var LogService
*/
private $logService;
/**
* ApiKeyAuthenticationMiddleware constructor.
* @param ApiModel $apiModel
* @param LogService $logService
*/
public function __construct(ApiModel $apiModel, LogService $logService)
{
$this->apiModel = $apiModel;
$this->logService = $logService;
}
/**
* @param ServerRequestInterface $request
* @param ResponseInterface $response
* @param callable $next
* @return ResponseInterface
* @throws \Dibi\Exception
*/
public function __invoke(ServerRequestInterface $request, ResponseInterface $response, callable $next): ResponseInterface
{
$this->apiModel->logRestApiResponse($request, $response);
return $next($request, $response);
}
}
public function logRestApiResponse(ServerRequestInterface $request, ResponseInterface $response): void
{
$body = json_encode(json_decode($response->getBody()->getContents(), true));
$values = [
'CODE' => $response->getStatusCode(),
'BODY_1' => mb_substr($body, 0, 3999),
'BODY_2' => mb_substr($body, 4000, 3999),
'ID_LOG_REST_API_REQUEST' => $request->getAttributes()['id_request'],
];
$this->db->query("INSERT INTO LOG_REST_API_RESPONSE %v", $values);
}
Moc děkuju
Editoval Croc (26. 7. 2019 10:07)

- Felix
- Nette Core | 1271
Ahoj, zkus tohle:
public function __invoke(ServerRequestInterface $request, ResponseInterface $response, callable $next): ResponseInterface
{
if ($request->getUri()->getPath() === '/api-rest/v1/') {
return $next($request, $response);
}
$id = $this->apiModel->logRestApiRequest($request);
$res = $next($request->withAttribute('id_request', $id), $response);
$this->apiModel->logRestApiResponse($res);
return $res;
}