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

Rtransat's avatar

Create API wrapper, best practice

Hi,

I want to wrap an API in a custom package. But I'm wondering what are the best practice to do this ?

I was thinking something like that but I want something simple. The API I want to use has only GET request. Do I need a Client class for example ?

What are the best practice for building an api wrapper ?

Thx

0 likes
8 replies
Rtransat's avatar

Thx for your awnser. But I don't want to create an API from scratch, just wrapping the API calling the URI and return the response in my package.

bobbybouwmann's avatar

You still need to do some coding to return the correct values...

What is your ultimate use case here? If we know your in and output we might have a solution for you

martinbean's avatar

@Rtransat What API are you wrapping? Is there a case for wrapping the API at all (i.e. are you using multiple services to fetch the same type of data)?

Usually, you would create an interface, and then have classes that implement those methods, but themselves wrap a client library.

I realise that’s a bit much to take in. @JeffreyWay did a video not so long ago where he subscribed users to a newsletter, but wrapped the MailChimp API in case you wanted to switch to an alternative service like Campaign Monitor. I can’t for the life of me remember which lesson this was though. That scenario would yield interfaces/classes like this, though:

interface NewsletterService
{
    public function subscribe($email);
}
class MailChimp implements NewsletterService
{
    public function __construct(MailChimpClient $client)
    {
        $this->client = $client;
    }

    public function subscribe($email)
    {
        $this->client->subscribeUser($email);
    }
}
class CampaignMonitor implements NewsletterService
{
    public function __construct(CampaignMonitorClient $client)
    {
        $this->client = $client;
    }

    public function subscribe($email)
    {
        $this->client->addUser($email);
    }
}

Please note: I made the class names of the MailChimp and Campaign Monitor clients up; I don’t actually know what their class names are off-hand. But if you look at the implementations, you’ll see both my classes implement the NewsletterService interface and thus a subscribe method, but the methods I’d call on the underlying $client class are different.

Hopefully this should point you in the right direction, as you don’t mention what scenario you need to wrap APIs for, so you should be able to take this example and apply it to your scenario.

1 like
Rtransat's avatar

Hey ! Sorry for the delay :/

I want to wrap a mashape api

I did some research and I think I'm going to use Guzzle for that. But I have a problem. I bind my facade like this :

Facade:

<?php

namespace Rtransat\HearthstoneApi;

use Illuminate\Support\Facades\Facade;

class HearthstoneApiFacade extends Facade
{
    protected static function getFacadeAccessor()
    {
        return 'hearthstone-api';
    }
}

ServiceProvider:

<?php

namespace Rtransat\HearthstoneApi;

use GuzzleHttp\Client;
use Illuminate\Support\ServiceProvider;

class HearthstoneApiServiceProvider extends ServiceProvider
{
    /**
     * Bootstrap the application services.
     *
     * @return void
     */
    public function boot()
    {
    }

    /**
     * Register the application services.
     *
     * @return void
     */
    public function register()
    {
        $this->app->bind('hearthstone-api', function ($app) {
            $base_uri = "https://omgvamp-hearthstone-v1.p.mashape.com/";
            $client = new Client([
                'base_uri' => $base_uri,
                'headers' => ['X-Mashape-Key' => 'API_KEY']
            ]);
            return new HearthstoneApi($client);
        });
    }
}

Wrapper class:

<?php

namespace Rtransat\HearthstoneApi;

use GuzzleHttp\Client;

class HearthstoneApi
{
    protected $client;

    public function __consutrct(Client $client)
    {
        $this->client = $client;
    }
    
    public function getCards()
    {
        dd($this->client);
    }
}

routes.php:

use Rtransat\HearthstoneApi\HearthstoneApi;

Route::get('/', function () {
    Hearthstone::getCards();
});

The die and dump return null but I don't know why in the IoC (HearthstoneApi class) the $client from ServiceProvider is not passed ?

Rjs37's avatar
Rjs37
Best Answer
Level 2

@Rtransat Only thing I can see is a typo in your construct function name. Though I'm assuming that's a typo in the post and not the code? Other than that I can't see anything blatant. It looks very much like how I bind my own service providers.

I'm currently working on wrapping multiple gaming api's myself, also using Guzzle. I currently use an API Service Provider to register the Game specific API Service Providers and their aliases. Rather than interfaces (as I have some different functions) I use abstraction. I could do with refactoring that but I did have plans to also implement some social API's too meaning I'd need multiple sets of Interfaces (GameInterface, SocialInterface) if I went that route.

If anyone's interested in seeing some simplified code samples of the above, let me know. I'm pretty happy with what I've come up with so far.

EDIT: I do like that example you provided though martin, that does give me a few ideas. Though it'd mean I'd need a separate service provider, facade, api class (to implement the interface) and client (which could handle my custom private logic) for each game api. It does actually sound a lot cleaner.

1 like
Rtransat's avatar

@Rjs37 F*ck me. The typo issue is real in my real code too -_-'. I will test again this evening but I hope it's just that :p

1 like

Please or to participate in this conversation.