Je suis en train de mettre en œuvre un service utilisant Slim 4 Cadre qui reviendra à peu près aux réponses JSON. J'essaie de garder toutes les réponses uniformes avec une structure similaire à celle-ci:
{
"status": "success",
"data": {"foo": "bar"} // the actual data relevant to the request
"messages": []
}
Dans le format le plus élémentaire, il s'agit du code que je devrais faire pour faire des réponses comme celle-ci:
public function __invoke(ServerRequestInterface $request, ResponseInterface $response): ResponseInterface {
// Do something
$response
->getBody()
->write(json_encode([
'status' => 'success',
'data' => [
'foo' => 'bar'
],
'messages' => [],
]));
return $response
->withHeader('Content-Type', 'application/json')
->withStatus(200);
}
En ce moment, j'utilise une classe d'assistance de base qui enveloppe essentiellement la majeure partie de cette chaudière en quelques fonctions statiques. Je peux donc écrire une réponse comme celle-ci:
public function __invoke(ServerRequestInterface $request, ResponseInterface $response): ResponseInterface {
// Do something
$data = ['foo' => 'bar'];
return APIResponse::success($response, $data)->into();
}
Cependant, maintenant, je rencontre un problème dans lequel j'aimerais apporter les réponses légèrement plus complexes, ce qui nécessiterait des dépendances supplémentaires, telles que des classes de sérialisement personnalisées. L'option naïve serait de continuer à passer des dépendances supplémentaires à APIResponse::success($response, $serializer, ..., $data)
, mais c'est évidemment mauvais et non une bonne option à long terme.
Une autre option que j'ai pensé serait de faire un APIResponseFactory
, qui prendrait des dépendances dans le constructeur et être remplie via PHP-DI. Ce serait un peu plus propre, mais chaque gestionnaire de route devrait avoir l'usine injectée et je devrais toujours passer manuellement $response
À chaque fois.
return $responseFactory->success($response, $data);
Donc, ce que je considère maintenant, c'est essayer de construire une classe personnalisée qui impliquerait ResponseInterface
, permettant ainsi de construire automatiquement dans les assistants de la batterie dans chaque gestionnaire de demande automatiquement. Je cherchais sur la mise en œuvre actuelle de la réponse à la PSR7 qui est utilisée dans mon projet et que les commentaires du code ont indiqué que la classe ne doit jamais être étendue et suggéré à l'aide d'un motif de décorateur. Il s'agit donc d'une implémentation de pseudocode de base que j'ai faite pour mon idée actuelle.
class MyCustomResponse implements ResponseInterface {
private $serializer;
private $actualResponse;
// any other dependencies
public function __construct(ResponseInterface $actualResponse, Serializer $serializer /*, other dependencies */) {
$this->actualResponse = $actualResponse;
$this->serializer = $serializer;
}
// Use this class as a decorator and pass all ResponseInterface calls to the external implementation
// EDIT: It looks like I can't use `__call` to fulfill the interface, so I'd need to manually define to functions, but you get the Gist.
public function __call($name, $args) {
return $this->actualResponse->$name(...$args);
}
public function success($data) {
$this->actualResponse
->getBody()
->write($this->serializer->serialize([
'status' => 'success',
'data' => $data,
'messages' => [],
]));
$this->actualResponse
->withHeader('Content-Type', 'application/json')
->withStatus(200);
return $this;
}
}
Ainsi, je voudrais (espérons-le) être capable de retourner des réponses comme celle-ci:
public function __invoke(ServerRequestInterface $request, ResponseInterface $response): ResponseInterface {
$data = ['foo' => 'bar'];
return $response->success($data);
}
Mes questions actuelles: Est-ce la bonne façon d'implémenter des méthodes d'assistance personnalisées pour les gestionnaires de réponse PSR-7? Y a-t-il une meilleure façon? L'écriture est-elle des fonctions d'assistance comme cette mauvaise pratique? Les interfaces PSR-7 semblent être, faute d'une meilleure description, de faible niveau de celacer et de verbeuse, ce qui me fait craindre que la rédaction d'une enveloppe comme celle-ci va en quelque sorte contre l'intention de la norme. Y a-t-il d'autres moyens de suivre la norme mais de réduire la chaudière et de garder les réponses uniformes?
Une "belle" action de contrôleur return $response->success($data);
peut être effectuée via
C'est une mauvaise pratique
{"status":"", "data":[], "messages": []}
format peut changerOublié de la ResponseInterface $response
argument, comment s'est-il fait avec le array $args
argument.
Injecter l'usine de réponse à chaque contrôleur, de sorte que vos actions ressemblaient à
public function __invoke(ServerRequestInterface $request): ResponseInterface
{
// Do something
return $this->responseFactory->createJson($data);
// OR
//return $this->responseFactory->createSomethingElse();
}