Ajeesh
Ajeesh

Reputation: 5860

API Calls in Laravel Repository Model

I am developing a web application in which I will be using third party API integrations (Payment gateways, SMS Vendors, Emailing services like mailchimp, other external APIs). My application will be having the repository pattern which will have repositories associated with each of my models and my controllers will be utilising the repository functions.

Now where does all my API integrations comes in? Should I be keeping all my API integrations in a single repository?

Example :

If I have a SMS provider Valuefirst, how does my Laravel repository design look like?

My SMS interface

interface ISmsProvider {
    public function sendSms($mobileNo,$msg);
}

My ValueFirst (SMS Provider) repository

class ValueFirstRepository implements ISmsProvider {
    public function sendSMS($mobieNo,$msg)
    {
       //API Call to ValueFirst SMS provider
       // Any database insertions/updates to SMS model
       // Any file logs
    }
}

Assuming I have a service provider class where I have done the binding of the interface and repository my controller will look like

SMS Controller

class SmsController extends BaseController {
    // ISmsProvider is the interface
    public function __construct(ISmsProvider $sms)
    {
        $this->sms = $sms;
    }

    public function sendSMS()
    {
        $mobileNo = '9999999999';
        $msg = 'Hello World!';
        $users = $this->sms->sendSMS($mobileNo,$msg); 
    }    
}

My questions

  1. Is this the right approach to an API integration using repository pattern?
  2. Does anything related to any database activities happens in the ValueFirst repository? Eg : If I want to update a record after the API response from ValueFirst, do I do it in the repository?
  3. If it's right , can someone show me how the model interactions happens from the repository?
  4. Now if I need to choose between ValueFirst or any other vendor how does that happens? How can I do it from the controller?

I will be using this project as a skeleton for my application

l5-Repository

Please help me with this design, I am fairly new to Laravel / repository pattern. Trying to learn stuff. TIA :)

Upvotes: 2

Views: 2826

Answers (1)

Moppo
Moppo

Reputation: 19285

Your approach seems pretty good to me but there is something i would improve

First of all I would keep the ValueFirstRepository class with the only resposability of managing your SMS API, and inject a specific repository class ( SmsRepository ) to interact with the DB through eloquent ( or only a model if you don't need a repository )

The important point here is to keep the resposability of managing your API in one class and the responsability of interacting with the DB in another:

ValueFirstRepository

class ValueFirstRepository implements ISmsProvider 
{
    //INJECT REPOSITORY CLASS TO INTERACT WITH DB
    public function __construct(SmsRepository $smsRepo )
    {
        $this->smsRepo = $smsRepo;    
    }

    //this method will be called from your controller
    public function sendSMS($mobieNo,$msg)
    {
       //API CALL
        $info = this->sendSMSAPI($mobieNo,$msg);

       //DB CALL
        $this->smsRepo->save( $info );

       // Any file logs
    }

    //this will actually interact with the API
    protected function sendSMSAPI($mobieNo,$msg)
    {
       //API Call to ValueFirst SMS provider
    }

}

A litte variant to this solution could be using events, and fire events in your ValueFirstRepository class when a sms is sent, and respond to that event implementing some listeners that will do other operations related to the event

Another alternative solution could be to handle the steps directly in your controller:

SMS Controller

//INJECT THE DEPENDECIES IN YOUR CONTROLLER
public function __construct(ISmsProvider $sms, SmsRepository $smsRepo )
{
    $this->sms = $sms;
    $this->smsRepo = $smsRepo;
}

public function sendSMS()
{
    //send SMS
    $mobileNo = '9999999999';
    $msg = 'Hello World!';
    $info= $this->sms->sendSMS($mobileNo,$msg);

    //use the model to save data
    this->$smsRepo->save($info); 
} 

This time the dependency of SmsRepository would be injected in the controller, instead of the ValueFirstRepository class, and the controller's methods would be a litte more big, but it's up to you to decide the best way for you

For the last question: if you want to change your vendor provider, you could use Laravel's capability to bind interfaces to implementation through the bind method:

App::bind( App\ISmsProvider::class , App\ValueFirstRepository::class );

This will tell laravel wich class inject when requesting a specific interface. So, in this case, when a ISmsProvider interface is requested, Laravel will automatically inject a ValueFirstRepository concrete instance.

If you want to change the vendor you should only change the line to:

App::bind( App\ISmsProvider::class , App\AnotherSMSVendorRepository::class ); 

and the AnotherSMSVendorRepository class will be injected instead of ValueFirstRepository

Upvotes: 3

Related Questions