minaremonshaker's avatar

Passing the request to a service method is a good practice or not ?

hi Merry Christmas! I have a UsersService class with a method that handles filtering and sorting data from the request. Is it good practice to pass the Request object directly to this service method (or inject it via the service provider), or should I avoid it? If not, what are the better alternatives?

note: i am using spaite query builder package

0 likes
4 replies
LaryAI's avatar
Level 58

Passing the entire Request object directly to your service methods is generally not recommended as a best practice. Here’s why and what you can do instead:

Why Avoid Passing the Request Directly?

  • Separation of Concerns: Service classes should be decoupled from HTTP specifics, making them easier to test and reuse (e.g., in CLI scripts or jobs).
  • Testing: Passing plain arrays or DTOs makes unit testing much easier without needing to mock HTTP requests.
  • Clarity: It’s clearer what data your service expects when you pass only the needed parameters.

Better Alternatives

1. Extract Only Needed Data and Pass as Arguments

In your controller, extract only what your service needs:

public function index(Request $request, UsersService $usersService)
{
    $filters = $request->only(['name', 'email', 'sort']);
    $users = $usersService->filterAndSort($filters);

    return response()->json($users);
}

Then, in your service:

class UsersService
{
    public function filterAndSort(array $filters)
    {
        // Use $filters['name'], $filters['email'], $filters['sort'] as needed
        // Example with Spatie Query Builder
        return QueryBuilder::for(User::class)
            ->allowedFilters(['name', 'email'])
            ->allowedSorts(['name', 'email'])
            ->get();
    }
}

2. Use Data Transfer Objects (DTOs)

For even more explicit typing and clarity, create a DTO to represent your filters:

class UserFilterData
{
    public function __construct(
        public ?string $name,
        public ?string $email,
        public ?string $sort
    ) {}
}

And then:

public function index(Request $request, UsersService $usersService)
{
    $filterData = new UserFilterData(
        $request->input('name'),
        $request->input('email'),
        $request->input('sort')
    );
    $users = $usersService->filterAndSort($filterData);

    return response()->json($users);
}

Summary

  • Avoid injecting or passing the entire Request object to services.
  • Extract and pass just the relevant data as an array or a DTO.
  • This approach ensures better separation of concerns, improved testability, and cleaner code.

Let me know if you’d like to see a more concrete example with the Spatie Query Builder!

vincent15000's avatar
Level 63

According to me, it's not a good pratice.

A service method should not be dependant on a request and should only receive the minimum data it requires.

minaremonshaker's avatar

ok , i have extracted the data from the request in the controller using $request->only([]) and passed it to the service method as an array

1 like
martinbean's avatar

@minaremonshaker The entire point of services is to have a class that you can use in a variety of contexts: HTTP requests, CLI commands, queued jobs, etc. If you pass a HTTP request to your service, then you’re restricting your service to be usable in a HTTP context only. So no, it’s not good practice.

1 like

Please or to participate in this conversation.