DEV Community

Cover image for Building a simple Referral System API with Laravel 11
Samson Ojugo
Samson Ojugo

Posted on • Edited on

Building a simple Referral System API with Laravel 11

With the use of special referral codes, referral systems are an effective marketing technique that encourages current customers to promote business offerings. For those who are new to using Laravel 11 and want to handle user referrals through APIs, this tutorial will show you how to create a basic referral system API.

Let's get started.

Prerequisites:

  • Basic understanding of PHP, Laravel concepts, and RESTful APIs
  • A local development environment with Laravel 11 installed
  • A database (e.g., MySQL) configured with Laravel

Step 1: Project Setup and Modify the User Migration Schema

Create a new Laravel project using the Artisan command and navigate to the project directory. We'll need a table to store user information. Laravel provides a User model by default.

Go to the users migration and modify accordingly.

 Schema::create('users', function (Blueprint $table) {
            $table->id();
            $table->string('name');
            $table->string('email')->unique();
            $table->timestamp('email_verified_at')->nullable();
            $table->rememberToken();
            $table->string('referral_code')->index()->unique();
            $table->unsignedBigInteger('referred_by')->nullable();
            $table->integer('referral_count')->default(0);
            $table->string('password');    
            $table->timestamps();

            $table->foreign('referred_by')->references('id')->on('users')->onUpdate('cascade')->onDelete('set null');
        });
Enter fullscreen mode Exit fullscreen mode

Then run the php artisan migrate to run your migrations.

Step 2: Define API route

We'll create two main API endpoints to manage referrals:

  • POST /users - This endpoint will handle user registration and potentially generate a referral code for the new user.

  • GET /users/{user}/referrals - This endpoint will retrieve referral data for a specific user

Enable API routing using the install:api Artisan command and define the route in your routes/api.php file.

Note:

The install:api command installs Laravel Sanctum, which provides a robust, yet simple API token authentication guard which can be used to authenticate third-party API consumers, SPAs, or mobile applications. In addition, the install:api command creates the routes/api.php file: read more https://laravel.com/docs/11.x/routing.

Route::prefix('/users')->group(function () {
    Route::post('/', [UserReferralProgramController::class, 'store']);
    Route::get('/{user}/referrals', [UserReferralProgramController::class, 'fetchUserReferral']);
});
Enter fullscreen mode Exit fullscreen mode

Consider using versioning in your API URL structure (e.g., /api/v1/users) to maintain flexibility for future changes. You may change the prefix by modifying your application's bootstrap/app.php file.

->withRouting(
        web: __DIR__ . '/../routes/web.php',
        api: __DIR__ . '/../routes/api.php',
        commands: __DIR__ . '/../routes/console.php',
        health: '/up',
        apiPrefix: 'api/v1',
    )
Enter fullscreen mode Exit fullscreen mode

Step 3: Define Methods in your Controller

Run the command php artisan make:controller Api/UserReferralProgramController
Goto app\Http\Controllers\Api\UserReferralProgramController.php and define the methods. Later, we shall return to the controller.

class UserReferralProgramController extends Controller
{
    /**
     * Store a newly created resource in storage.
     */
    public function store(UserStoreRequest $request): void
    {
    }

    /**
     * fetch user referrals.
     */
    public function fetchUserReferral(User $user): void
    {
    }
}
Enter fullscreen mode Exit fullscreen mode

Step 4: Utilize the service class(if applicable).

run the command php artisan make:class Service/ReferralCodeGenerator to create the class

<?php

namespace App\Service;

use App\Models\User;

class ReferralCodeGenerator
{
    /**
     * Generates a random referral code.
     *
     * This method generates a random string of specified length using the provided character set.
     * It then checks for existing codes in the database and regenerates if necessary.
     *
     * @return string The generated referral code.
     * 
     * @throws \Exception If an error occurs during code generation or validation.
     */
    public function generate(): string
    {
        $codeLength = 10;
        $characters = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
        $code = '';

        $code = substr(str_shuffle(str_repeat($characters, 5)), 0, $codeLength);

        return $this->checkAndRegenerate($code);
    }

    /**
     * Checks if a referral code already exists in the database and regenerates if necessary.
     *
     * This method takes a generated referral code as input and checks if it exists in the database.
     * If the code already exists, it regenerates a new code using the `generate` method and calls itself recursively to check again.
     * This process continues until a unique, non-existing code is found.
     *
     * @param string $code The referral code to be checked.
     * 
     * @return string A unique, non-existing referral code.
     * 
     */
    private function checkAndRegenerate(string $code): string
    {
        if (User::where('referral_code', $code)->exists()) {
            return $this->checkAndRegenerate($this->generate());
        }

        return $code;
    }

    /**
     * Finds a user by referral code and increments their referral count in a single database query.
     *
     * This method takes a referral code as input and attempts to find a matching user in the database.
     * If a user is found, it atomically increments their `referral_count` by 1 and retrieves the user's ID.
     * 
     * This method utilizes a single database query with Laravel's `update` method and raw expressions for efficiency.
     *
     * @param string $referralCode The referral code to be checked.
     * 
     * @return int|null The user ID if found, otherwise null.
     *
     */
    public function getUserIdByReferralCodeAndIncrementCount(string $referralCode): int|null
    {
        $userId = User::where('referral_code', $referralCode)->value('id');

        if ($userId) {
            $this->incrementReferralCount($userId);
            return $userId;
        }
        return null;
    }

    private function incrementReferralCount(int $userId): void
    {
        User::where('id', $userId)->increment('referral_count');
    }
}

Enter fullscreen mode Exit fullscreen mode

Code Explanation:

The ReferralCodeGenerator class provides functionality to generate unique referral codes and manage user referral counts. Here's a summary:

  1. generate Method: Creates a random 10-character referral code using a specified character set and ensures its uniqueness by checking against the database.
  2. checkAndRegenerate Method: Recursively verifies the uniqueness of a referral code and regenerates it if necessary.
  3. getUserIdByReferralCodeAndIncrementCount Method: Finds a user by referral code, increments their referral count atomically, and returns the user's ID.
  4. incrementReferralCount Method: Increments the referral_count of a user by their ID.

This class ensures that generated referral codes are unique and facilitates updating user referral counts efficiently.

Step 8: Modify our existing Controller

Let’s go back to our controller app\Http\Controllers\Api\UserReferralProgramController.php and make some modifications.

class UserReferralProgramController extends Controller
{

    /**
     * Create a new class instance.
     */
    public function __construct(public ReferralCodeGenerator $referralCodeGenerator)
    {
        //
    }

    /**
     * Store a newly created resource in storage.
     */
    public function store(UserStoreRequest $request): JsonResponse
    {

        $validatedData = $request->validated();

        $referredBy = null;

        if ($request->has('referral_code')) {
            $referredBy = $this->referralCodeGenerator->getUserIdByReferralCodeAndIncrementCount($request->referral_code);
        }

        $requestData = array_merge(
            $validatedData,
            [
                'referred_by' => $referredBy,
                'referral_code' => $this->referralCodeGenerator->generate()
            ]
        );

        $user  = User::create($requestData);

        return response()->json([
            'message' => 'user created',
            'data' => $user
        ], Response::HTTP_CREATED);
    }

    /**
     * fetch user referrals.
     */
    public function fetchUserReferral(User $user): JsonResponse
    {
        $referrals = User::where('referred_by', $user->id)->get();

        return response()->json([
            'message' => 'success',
            'data' => [
                'referrals_count' => $user->referral_count,
                'referrals' => $referrals
            ]
        ], Response::HTTP_OK);
    }
}

Enter fullscreen mode Exit fullscreen mode

In our controller method:

  • I Initialized the controller with a ReferralCodeGenerator instance, which is used for generating and validating referral codes.
  • Also validated the incoming request data (name, email, password, etc.).
  • If a referral_code parameter is present in the request, use it to find the referring user.
  • Created a new User model instance with the provided data and generated code.
  • Saved the user to the database and potentially update the referring user's referral count
  • Returned a successful response with relevant user information (excluding password) or an error response in case of validation issues or database errors.

Remember

This example has been simplified. Ensure that your system is production-ready by integrating strong authentication methods, Database transaction, resource to transform the result, extensive error handling, and extra features depending on your requirements.

Using Laravel 11, you can create a robust referral system API that facilitates user growth and acquisition for your application by following these instructions and experimenting with advanced features.

Test our Endpoint on POSTMAN

  • {{url}}/api/v1/users to store users

register user with referal code

  • {{url}}/api/v1/users/:userId/referrals to fetch user referrals

fetch user with their referrals

You can get the complete code from https://github.com/quitenoisemaker/customer_incentive_programs

Top comments (0)