Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

connecteev's avatar

Way to Defer Laravel's API Request Validation?

I have an API resource that accepts a request as such:

 public function create(StorePostRequest $request) {
 }

The problem is, when I send a POST request to this create() endpoint, the rules() defined in StorePostRequest.php kick in before the method is even called. I want to do some pre-validation and THEN validate with the rules() in the StorePostRequest.

The rules() that are defined in StorePostRequest.php kick in before the create() method is even called.

    public function rules()
    {
        return [
            'title'                  => [
                'min:10',
                'max:255',
                'required',
            ],
            'slug'                   => [
                'min:10',
                'max:255',
                'required',
                // 'unique:posts',
            ],
            'user_id'                => [
                'required',
                'integer',
            ],
        ];

For example, the user_id should be retrieved from the Auth() session, and not get passed in. But I do want the rule to be there when the data gets stored to the posts table.

So, I changed the API to:

    // Note: if you accept a StorePostRequest $request, it automatically pre-validates based on rules() in StorePostRequest
    public function create(Request $request)
    {
        $loggedinUser = auth()->user();
        if (!$loggedinUser) {
            return response(["error" => "User is not logged in. User needs to be logged in to use this API."], Response::HTTP_FORBIDDEN);
        }
        $loggedinUserId = $loggedinUser->id;

        $requestData = $request->all();
        if (!isset($requestData['title'])) {
            return response(["error" => "title is required"], Response::HTTP_BAD_REQUEST);
        }
        if (!isset($requestData['body'])) {
            return response(["error" => "body is required"], Response::HTTP_BAD_REQUEST);
        }
        if (!isset($requestData['status'])) {
            return response(["error" => "status is required"], Response::HTTP_BAD_REQUEST);
        }
        $requestData['slug'] = $this->createUniquePostSlug($request->title);
        $requestData['user_id'] = $loggedinUserId;
        $requestData['description'] = $request->title;
        $requestData['reading_time_minutes'] = ceil(str_word_count(strip_tags($requestData['body'])) / 200); // assuming an average reading speed of 200 wpm

        $post = Post::create($requestData);

        return (new PostResource($post))
            ->response()
            ->setStatusCode(Response::HTTP_CREATED);
    }

However now I have to do a bunch of manual validation (using isset($requestData) like I'm doing above. I want the StorePostRequest rules to kick in, but after I do some request validation myself. Is there a way to do this? Maybe there's a way to cast the Request object to the StorePostRequest? THoughts? And thanks in advance.

0 likes
4 replies
Sinnbeck's avatar

Untested, but I would guess you can just do this when you get to validation (you could probably use Validator::make in the same way if you prefer)

$validatedData = $request->validate(resolve(StorePostRequest::class)->rules());
connecteev's avatar

Thanks but that didn't quite work.

Solved it by doing this.

        // Validate the request with the rules() set in StorePostRequest.php
        $storePostRequest = new StorePostRequest();
        $validator = Validator::make($requestData, $storePostRequest->rules());
        if ($validator->fails()) {
            return response($validator->errors(), Response::HTTP_BAD_REQUEST);
        }
        $post = Post::create($requestData);
Sinnbeck's avatar
Sinnbeck
Best Answer
Level 102

Uhm that is exactly the same, except using Validator::make like i suggested

new StorePostRequest() and resolve(StorePostRequest::class)is the same as resolve() simply runs new on the class and injects parameters into construct if any are needed (typecasted).

In other words if you took the example and replaced with Validator::make i would be like this :)

$validator = Validator::make($request->all(), resolve(StorePostRequest::class)->rules());
connecteev's avatar

It's similar...thanks. I marked your answer the best answer.

Please or to participate in this conversation.