1

My Laravel project has a lot of controller methods which simply return nothing or void on success. I want (more precisely need) those methods to eventually return a 204 No Content response to the client. I would like to avoid adding return response()->noContent() to each and every controller method where I need it. However, if I do not, Laravel sends an 200 OK response with an empty body to the client.

The method Illuminate\Routing\Router::toResponse($request, $response) is responsible for this. The parameter $response equals the return value of the controller method. If the controller method returns nothing, $response equals null. The method toResponse($request, $response) matches the parameter $response against different conditions and if nothing matches toResponse($request, $response) creates a SymfonyResponse with status code 200 and an empty body. I would like to override this method and add another condition. If $response === null, then toResponse($request, $response) should create a SymfonfyResponse with status code 204.

My main problem is that I don't find any information how to make the framework to call my own implementation of the router class.

user2690527
  • 1,729
  • 1
  • 22
  • 38

1 Answers1

1

Found a solution which is much easier than overwriting the Router. I can use a middleware which modifies the response after the controller method has run, but before the response is sent to the client: a so-called response middleware (see Laravel Documentation "Middleware $ Responses").

namespace App\Http\Middleware;

use Closure;
use Illuminate\Http\Request;
use Symfony\Component\HttpFoundation\Response;

/**
 * Ensures that responses with empty content return status code 204.
 *
 * This fixes a bug in Laravel.
 */
class FixStatusCode {
  /**
   * Handle an incoming request.
   *
   * @param Request  $request
   * @param \Closure $next
   *
   * @return Response
   *
   * @throws \InvalidArgumentException
   */
  public function handle(Request $request, Closure $next): Response {
    /** @var Response $response */
    $response = $next($request);
    
    if (empty($response->getContent())) {
      $response->setStatusCode(Response::HTTP_NO_CONTENT);
    }
    
    return $response;
  }
}

Then, I have to register this middleware like any other middleware in App\Http\Kernel::$middleware.

user2690527
  • 1,729
  • 1
  • 22
  • 38