Mastering The Laravel App Service Pattern

Laravel PHP Service Pattern
Profile Picture Joton Sutradharโ€ข ๐Ÿ“– 6 min read โ€ข ๐Ÿ“… 27th May 2025

Heads up!

Check my blogs on Dev.to and Medium!

As your Laravel application grows, keeping your code organized becomes more important than ever. A bloated controller quickly becomes hard to read, test, and maintain. One of the best solutions to this problem is using the Service Pattern — a pattern that helps separate your business logic from your controllers.

In this blog, we'll dive deep into how to implement the Service Pattern in Laravel. We’ll walk through the folder structure, build a real-world example with custom Form Requests, and show how the service layer improves code clarity and maintainability — all without using a Repository.

๐Ÿง  What is the Service Pattern?

The Service Pattern is a design principle where you offload complex or reusable business logic into a Service class. This keeps your controllers clean and your application logic in one place, making it easier to test and reuse.

โœจ Why use the Service Pattern?

  • Separation of concerns: Controllers handle requests, services handle logic.

  • Testability: You can write unit tests for service methods easily.

  • Reusability: Use the same service in multiple places.

  • Cleaner Controllers: Easier to read, maintain, and debug

๐Ÿ“ Folder Structure

To organize your service logic effectively, here’s a commonly used folder structure:

app/
โ”œโ”€โ”€ Http/
โ”‚   โ”œโ”€โ”€ Controllers/
โ”‚   โ”‚   โ””โ”€โ”€ AuthController.php
โ”‚   โ”œโ”€โ”€ Requests/
โ”‚   โ”‚   โ””โ”€โ”€ RegisterUserRequest.php
โ”‚
โ”œโ”€โ”€ Services/
โ”‚   โ””โ”€โ”€ Auth/
โ”‚       โ””โ”€โ”€ RegisterService.php
โ”‚
โ”œโ”€โ”€ Models/
โ”‚   โ””โ”€โ”€ User.php

This structure:

  • Places each concern in its own folder

  • Makes it easier to scale and add features

  • Keeps logic modular and traceable

๐Ÿ’ก Use Case: User Registration

Let’s say we’re building a simple user registration feature. We want:

  • Validation using a custom Form Request

  • Business logic inside a Service

  • A clean, readable controller

๐Ÿงพ Step 1: Create a Custom Form Request

We’ll use Laravel’s FormRequest to handle validation cleanly.

File: app/Http/Requests/RegisterUserRequest.php

namespace App\Http\Requests;

use Illuminate\Foundation\Http\FormRequest;

class RegisterUserRequest extends FormRequest
{
    public function authorize(): bool
    {
        // Can add authorization logic here
        return true;
    }

    public function rules(): array
    {
        return [
            'first_name' => 'required|string|max:255',
            'last_name'  => 'required|string|max:255',
            'email'      => 'required|email|unique:users,email',
            'password'   => 'required|string|min:8|confirmed',
        ];
    }
}

Here:

  • authorize() lets us control access (e.g. based on roles).

  • rules() defines the validation logic.

When you use this in a controller, Laravel auto-validates the request.

โš™๏ธ Step 2: Create the Service Class

This class will handle all the registration logic.

File: app/Services/Auth/RegisterService.php

namespace App\Services\Auth;

use App\Models\User;
use Illuminate\Support\Facades\Hash;

class RegisterService
{
    public function register(array $data): User
    {
        return User::create([
            'first_name' => $data['first_name'],
            'last_name'  => $data['last_name'],
            'email'      => $data['email'],
            'password'   => Hash::make($data['password']),
        ]);
    }
}

Now all business logic — such as password hashing, user creation — lives here. It’s reusable and easy to test.

๐ŸŽฎ Step 3: Use Service in Controller

Now, let’s call our service in the controller. This keeps the controller clean and focused on handling HTTP.

File: app/Http/Controllers/AuthController.php

namespace App\Http\Controllers;

use App\Http\Requests\RegisterUserRequest;
use App\Services\Auth\RegisterService;
use Illuminate\Http\JsonResponse;

class AuthController extends Controller
{
    protected RegisterService $registerService;

    public function __construct(RegisterService $registerService)
    {
        $this->registerService = $registerService;
    }

    public function register(RegisterUserRequest $request): JsonResponse
    {
        $user = $this->registerService->register($request->validated());

        return response()->json([
            'message' => 'User registered successfully.',
            'user'    => $user,
        ], 201);
    }
}

Let’s break this down:

  • The constructor injects the RegisterService using Laravel’s service container.

  • The register() method receives validated data from RegisterUserRequest.

  • It delegates logic to the service, and simply returns a response.

โœ… Now your controller is lean, readable, and testable.

๐Ÿงช How to Test Your Service

Because your service is decoupled from the controller, you can unit test it easily:

public function test_user_can_be_registered()
{
    $service = new RegisterService();

    $user = $service->register([
        'first_name' => 'John',
        'last_name'  => 'Doe',
        'email'      => '[email protected]',
        'password'   => 'password123',
    ]);

    $this->assertDatabaseHas('users', ['email' => '[email protected]']);
}

๐Ÿงผ Final Thoughts

The Service Pattern is a proven architectural approach in Laravel for building scalable, maintainable apps. It shines when:

  • You need to keep controllers slim

  • You want reusable business logic

  • You want to write better tests

๐Ÿ›  Summary

Component Responsibility
Controller Handles HTTP requests/responses
Form Request Handles validation
Service Handles business logic (e.g. registration)
Model Represents database entity
Related Blogs
Clean Code, Scalable Systems: The Abstract Service Advantage In Laravel
PHP Laravel Abstraction Abstract Service Joton Sutradhar

Alright, Laravel developers, let's talk shop. We love Laravel for its elegance, convention over configuration, and how quickly it lets us build. But as our applications grow, even in a framework as opinionated as Laravel, we can fall into traps: repeating the same logic across different "service" classes, inconsistent data handling, or struggling to manage complex workflows.

Profile Picture Joton Sutradhar โ€ข ๐Ÿ“– 17 min read โ€ข ๐Ÿ“… 20th June 2025
The Art Of Debugging: Why It Matters And How To Master It ๐Ÿš€
Debugging PHP Web Development Programming Code Quality Error Handling Xdebug Troubleshooting

Debugging is one of the most crucial skills every developer must master, yet it's often overlooked in formal education. Whether you're a beginner writing your first "Hello World" program or a seasoned developer working on complex enterprise applications, debugging will be your constant companion throughout your coding journey.

Profile Picture Joton Sutradhar โ€ข ๐Ÿ“– 11 min read โ€ข ๐Ÿ“… 9th June 2025
๐Ÿš€ Laravel Horizon: A Step-by-Step Guide For Managing Queues Like A Pro
Queue Jobs Laravel Horizon

Queues are essential for building scalable and performant Laravel applications. Whether you're sending emails, processing files, or executing time-consuming tasks, queues offload work and keep your app fast. But how do you monitor and manage them effectively?

Profile Picture Joton Sutradhar โ€ข ๐Ÿ“– 4 min read โ€ข ๐Ÿ“… 2nd June 2025
Subscribe to my newsletter

Get recent projects & blog updates to your inbox.

I never share your email. Read our privacy policy.

© 2025 Joton Sutradhar. All rights reserved.