Creating a Custom Laravel Middleware for Consistent API Responses
This guide explains how to build and register a custom Laravel middleware that standardizes API responses by enforcing JSON format, formatting successful and error payloads, and optionally handling JWT authentication errors, improving clarity and developer experience.
When building APIs with Laravel, maintaining a consistent response format is crucial for clarity and usability. Whether a response is successful or an error, presenting data in a standardized way improves the developer experience.
This guide explores how to use a custom middleware in Laravel to achieve a uniform response structure.
Step 1: Create a Custom Middleware
We need to generate a middleware that will handle all API responses. Use the Artisan command to create the middleware:
php artisan make:middleware ApiResponseMiddlewareThe command creates a file named ApiResponseMiddleware in the app/Http/Middleware directory.
Step 2: Customize the Middleware
Open the newly created ApiResponseMiddleware.php file and update the handle() method as follows:
<?php
namespace App\Http\Middleware;
use Closure;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
use Throwable;
class ApiResponseMiddleware
{
/**
* Handle an incoming request.
*
* @param Request $request
* @param Closure(Request): (Response|RedirectResponse) $next
* @return JsonResponse
* @throws Throwable
*/
public function handle(Request $request, Closure $next)
{
$response = $next($request);
// Check if the request expects JSON
if (! $request->wantsJson() && ! $request->is('api/*')) {
// Force API requests to return JSON
return $next($request);
}
// Set the Accept header to application/json
$request->headers->set('Accept', 'application/json');
// If the response is a JsonResponse, format it
if ($response instanceof JsonResponse) {
$data = $response->getData(true);
// Create a standardized response structure
$formattedResponse = [
'success' => array_key_exists('success', $data) ? $data['success'] : $response->status() == 200,
'statusCode' => array_key_exists('statusCode', $data) ? $data['statusCode'] : $response->status(),
'statusDescription' => array_key_exists('statusDescription', $data) ? $data['statusDescription'] : ($response->status() == 200 ? 'Successful' : ''),
'data' => array_key_exists('data', $data) ? $data['data'] : ($response->status() == 200 ? $data : null),
];
// Return the formatted JSON response
return response()->json($formattedResponse, $response->status());
}
// Return the original response unchanged
return $next($request);
}
}The middleware checks whether the request needs JSON. If not, it passes the request to the next middleware. If JSON is required, it sets the Accept header to application/json to ensure the response is sent in the correct format.
It then checks whether the response is an instance of JsonResponse. If so, it decodes the response, builds a standardized structure, and returns the formatted JSON. Non‑JSON responses are returned unchanged.
Step 3: Register the Middleware
We need to add ApiResponseMiddleware to the $middlewareGroups array in app/Http/Kernel.php. Adding it to the api group makes it apply globally to all API routes:
protected $middlewareGroups = [
'web' => [
// other middleware...
],
'api' => [
// other middleware...
\App\Http\Middleware\ApiResponseMiddleware::class,
],
];Including the middleware in the api group ensures it runs for every API route.
Step 4: Ensure Controllers Return Consistent Responses
To fully benefit from the middleware, make sure your controllers return responses in the defined format, for example:
return response()->json([
'success' => true,
'statusCode' => 200,
'statusDescription' => 'Successful',
'data' => $yourData,
]);Step 5 (Optional): Prevent HTML Responses When Using JWT Tokens
To avoid returning HTML pages for invalid JWT tokens, customize Laravel's exception handler in App\Exceptions\Handler by overriding the render() method. The example below shows how to return a JSON error response for authentication failures and other exceptions.
<?php
namespace App\Exceptions;
use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Str;
use Throwable;
use Illuminate\Auth\AuthenticationException;
class Handler extends ExceptionHandler
{
protected $dontReport = [];
protected $dontFlash = ['password', 'password_confirmation'];
public function report(Throwable $exception)
{
parent::report($exception);
}
public function render($request, Throwable $e)
{
// Handle JWT authentication exceptions
if ($e instanceof AuthenticationException) {
return response()->json([
'success' => false,
'statusCode' => 401,
'statusDescription' => 'Unauthorized: Invalid JWT Token',
'data' => null,
], 401);
}
// Handle other API exceptions
if ($request->wantsJson() || $this->isApiRequest($request)) {
return $this->formatApiResponse($e);
}
return parent::render($request, $e);
}
protected function isApiRequest(Request $request): bool
{
// Adjust the condition to match your API routes
return Str::startsWith($request->path(), 'api/') || $request->expectsJson();
}
protected function formatApiResponse(Throwable $exception): JsonResponse
{
return response()->json([
'success' => false,
'statusCode' => $this->getStatusCode($exception),
'statusDescription' => $exception->getMessage(),
'data' => null,
], $this->getStatusCode($exception));
}
protected function getStatusCode(Throwable $exception)
{
return method_exists($exception, 'getStatusCode') ? $exception->getStatusCode() : 500;
}
}Following these steps, you can implement a custom Laravel middleware that consistently formats API responses, improving readability and usability for developers. Adjust the middleware as needed to suit specific API requirements, such as adding or removing fields or changing the response structure.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
php Courses
php中文网's platform for the latest courses and technical articles, helping PHP learners advance quickly.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
