web-dev-qa-db-fra.com

Comment effectuer une réponse personnalisée PSR-7 pour réduire la chaudière?

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?

9
404 Not Found

Une "belle" action de contrôleur return $response->success($data); peut être effectuée via

C'est une mauvaise pratique

  • Le {"status":"", "data":[], "messages": []} format peut changer
  • Dossier d'apparition, flux, etc.

Oublié 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();
}
2
cetver