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 | 1247
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;
}