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

Ashraam's avatar
Level 41

Building API: how to make it more smooth ?

Hi, i'm building a wrapper around an accountant API, I'd like to make it easy to use. With this I can manage customers and invoices / quotes....

Right now my API works like this

$api = new MyApi('my_token');

$customers = $api->getAllCustomers();

$customer = $api->getCustomer(14444);

$invoices = $api->getAllInvoices();

$invoice = $api->getInvoice(145);

There are a lot more methods by the way.

To do this, I have a main class Api.php that uses multiple traits (Customers, Invoices, ....) so all the customers logic is inside a file, the same for invoices....

First of all, are the trait good in this case ?

What I'd really want is to use my API like this:

$api = new Api('my_token');

$customers = $api->customers()->list();

$customer = $api->customer()->get(14444);

$invoices = $api->invoices()->list();

$invoice = $api->invoices()->get(145);

I can't use traits anymore because methods have the same name, so How could I achieve this ?

If you have any links that point to a tutorial or some examples, I'd take it.

Thank you

0 likes
7 replies
automica's avatar

I can use traits anymore because methods have the same name, so How could I achieve this ?

do you mean ' I can't'?

automica's avatar

If you need to use traits (and thats debatable) you'd add that on your Customer and Invoice class.

Is this a conventional laravel api with relationships to your customers and invoices within your Api model?

Ashraam's avatar
Level 41

For now it's a plain PHP package, not specific for Laravel.

But I may have found out how to do what I want but there must be a better solution I guess.

My main class looks like this

<?php

class Api {
   private $token;

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

  protected function client()
    {
        return new Client([
            'base_uri' => 'API_URL',
            'headers' => [
                'Content-type' => 'application/json',
                'Authorization' => "Token {$this->token}"
            ]
        ]);
    }

   public function customers() {
      return new Customers($this->token);
   }
}

My Customers class be like

<?php

class Customers extends Api {
   public function get() {
      try {
            $response = $this->client()->request("GET", "customers/{$id}/");
        } catch (Exception $ex) {
            throw $ex;
        }

        return json_decode($response->getBody()->getContents(), true);
   }
}

The downside here is each time I call customers, it will create a new instance of the guzzle client.

automica's avatar

can't you add the client within the constructor instead?

    public function __construct($token, Client $client) {
        $this->token = $token;
        $this->client = $client;
    }
Ashraam's avatar
Level 41

Yes but Customer extends Api so it will create two instances of the Guzzle client :/

aleahy's avatar

Just thought I would add another approach.

I was recently building a package to access an API similar to yours. What I did was let the API class be responsible for making the connection and doing the calls, using the same method regardless of the type of object you're dealing with.

The object model would be responsible for the api endpoints and the and it gets the endpoints and how to create the returned model from the model class.

Something like this:

$api = new Api($token, $client);
$customers = $api->list(Customer::class)

In the Api class:

public function list($entityClass) {
   $uri = $entityClass::LIST_ENDPOINT;
   
   $response = $this->client->request('GET', $uri);

   $json = $response->getBody()->getContents();

   return  $entityClass::makeListFromJson($json);
}

Please or to participate in this conversation.