DRY - Response method


#1

Hi, I’m reviewing my slim3 API code to cleanup and add some improvement. In my controllers there are a lot of repeated responses method as ie invalid fields, invalid request, not found item etc… they are all common response in different controllers :face_with_raised_eyebrow:

class UserController extends BaseController{
    public function updateUser(Request $request, Response $response){
      ...
      if (!$user instanceof User) {
          return $response->withJson(['Error occurred on creating User'], 500)
      }
      ...
    }

or

    public function showUser(Request $request, Response $response){
      ...
      if (!$user instanceof User) {
          return $response->withJson(['The user with id doesn\'t exist'], 500)
      }
      ...
    }

So, how can I use a global class (or trait?) to manage responses ?
I try to add methods in BaseController, ie

    public function sendErrorResponse($message)
    {
        return $response->withJson($message, 500);
    }

to use it in single controller

public function updateUser(Request $request, Response $response){
  ...
  if (!$user instanceof User) {
      return $this->sendErrorResponse('Error occurred on creating User')
  }
  ...
}

but clearly, it doesn’t know $response and crash …:scream:
ok, another option is to inject response to the baseController method:

use Psr\Http\Message\ResponseInterface as Response;

class BaseController
{
  ...
public function sendErrorResponse(Response $response, $message)
{
  return $response->withJson($message, 500);
}

and, for each method in controllers write like this:

public function updateUser(Request $request, Response $response){
  ...
  if (!$user instanceof User) {
      return $this->sendErrorResponse($response, 'Error occurred on creating User')
  }
  ...
}

The final think is to use a separeted class (ie App\Response\ErrorResponse) and extend Slim\Http\Response but seems to be not good.
What’s the best practice to manage a global class Response for controllers?


#2

I’m far from an expert on design patterns, but I do something very similar to your sendErrorResponse method in your BaseController.


#3

Thank you Tim!
About Response DRY I’m working with ResponseTrait and everything is ok with ->setResponse, but I never see it or similar especially from @akrabat repos … Any final suggest/example to handle Response object outside controller in Slim? Maybe I’m on the wrong way and the best practice is to use Response for each API controllers … :confused:

my trait example

trait ResponseTrait
{
    protected $statusCode = 200;
    protected $response;

    public function getStatusCode()
    {
        return $this->statusCode;
    }

    public function setStatusCode($statusCode)
    {
        $this->statusCode = $statusCode;
        return $this;
    }

    public function getResponse()
    {
        return $this->response;
    }

    public function setResponse($response)
    {
        $this->response = $response;
        return $this;
    }

    public function sendCustomResponse($status, $message)
    {
        return $this->response->withJson(['status' => $status, 'detail' => $message], $status);
    }