DEV Community

Viktor Le
Viktor Le

Posted on

How to detect a request is API or Web in laravel

I am working on a Project, of which the structure is based on Laravel and, my situation is to return a Validation Error JSON Format or Auto-Carried in Flashed Session (stored in $errors variable) given by a Request.
To strategize the JSON response format, I actually work with Handler Exception. So, I implement a custom ApiValidationErrorException class for Json Format, which looks like as bellow:

<?php

namespace App\Exceptions;

use Exception;
use Illuminate\Http\JsonResponse;
use Illuminate\Validation\ValidationException;
use Symfony\Component\HttpFoundation\Response;

class ApiValidationErrorException extends ValidationException
{
    public function render($request): JsonResponse
    {
        return new JsonResponse([
            // This is the array that you will return in case of an error.
            // You can put whatever you want inside.
            'message' => 'There were some errors',
            'status' => false,
            'additionalThings' => 'Some additional things',
            'errors' => $this->validator->errors()->getMessages(),
        ], Response::HTTP_UNPROCESSABLE_ENTITY);
    }
}
Enter fullscreen mode Exit fullscreen mode

then, call this custom class in Handler->register function, it looks like

<?php

namespace App\Exceptions;

use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler;
use Illuminate\Validation\ValidationException;
use Throwable;

class Handler extends ExceptionHandler
{

    /**
     * Register the exception handling callbacks for the application.
     */
    public function register(): void
    {
        $this->renderable(function (ValidationException $exception, $request) {
            throw ApiValidationErrorException::withMessages(
                $exception->validator->getMessageBag()->getMessages()
            );
        });

        $this->reportable(function (Throwable $e) {
            //
        });
    }
}

Enter fullscreen mode Exit fullscreen mode

However, this register throws a problem for returning errors on web request. Instead of displaying messages in HTML which is generated from blade templates, it returns a JSON response because the renderable method always throws ApiValidationErrorException format.

So, this definitely needs a if else statement here to control the response properly.

So, the conditional statement detect the request whether it is RESTful Request or Form Request. Alright, Laravel provides a method on request Object name wantsJson(), which checks the client request sends Accept=application/json in Header. So to use it, we have to set Accept=application/json in Header otherwise, this method returns false always. Then, I ask myself, is there any options to check API request? . Right, I search and search ... it comes up with a method, $request->is('api/*'). Utimately, the register() method looks like

    public function register(): void
    {
        $this->renderable(function (ValidationException $exception, $request) {
            if ($request->wantsJson() || $request->is('api/*')) {
                throw ApiValidationErrorException::withMessages(
                    $exception->validator->getMessageBag()->getMessages()
                );
            }

            return null;

        });

        $this->reportable(function (Throwable $e) {
            //
        });
    }
Enter fullscreen mode Exit fullscreen mode

I hope this post could help some of you strategize the reponse format in such a situation

Top comments (0)