Eloquent API Calls

Published on:

Time and again, I have spoken about API integrations, and each time I find an improvement from the last, once more into the fray.

I was recently tagged on twitter about an article called SDKs, The Laravel Way. This stood out as it somewhat mirrored how I do API integrations and inspired me to add my own two cents.

For the record, the article I mentioned is excellent, and there is nothing wrong with the approach taken. I feel like I can expand upon it a little with my lessons learned in API development and integrations. I won’t directly copy the topic as it is for an API I am not familiar with. However, I will take concepts in an API I am familiar with, the GitHub API, and go into some details.

When building a new API integration, I first organize the configuration and environment variables. To me, these belong in the services configuration file as they are third-party services we are configuring. Of course, you do not have to do this, and it doesn’t really matter where you keep them as long as you remember where they are!

// config/services.php

return [
    // other services

    'github' => [
        'url' => env('GITHUB_URL'),
        'token' => env('GITHUB_TOKEN'),
        'timeout' => env('GITHUB_TIMEOUT', 15),
    ],
];

The main things I make sure I do is store the URL, API Token, and timeout. I store the URL because I hate having floating strings in classes or app code. It feels wrong, it isn’t wrong, of course, but we all know I have strong opinions …

Next, I create a contract/interface - depending on how many integrations will tell me what sort of interface I may need. I like to use an Interface as it enforces a contract within my code and forces me to think before changing an API. I am protecting myself from breaking changes! My contract is super minimal though. I typically have one method and a doc block for a property I intend to add through the constructor.

/**
 * @property-read PendingRequest $request
 */
interface ClientContract
{
    public function send();
}

I leave the responsibility of sending the request to the client. This method will be refactored later, but I will go into detail later. This interface can live wherever you are most comfortable keeping it - I typically keep it under App\Services\Contracts but feel free to use your imagination.

Once I have a rough contract, I start building the implementation itself. I like to create a new namespace for each integration I build. It keeps things grouped and logical.

final class Client implements ClientContract
{
    public function __construct(
        private readonly PendingRequest $request,
    ) {}
}

I have started passing the configured PendingRequest into the API client, as it keeps things clean and avoids manual setup. I like this approach and wonder why I didn’t do this before!

You will notice I still need to follow the contract, as there is a step I need to take beforehand. One of my favorite PHP 8.1 features - Enums.

I create a method Enum for apps, I should make a package, as it keeps things fluid - and again, no floating strings in my application!

enum Method: string
{
    case GET = 'GET';
    case POST = 'POST';
    case PUT = 'PUT';
    case PATCH = 'PATCH';
    case DELETE = 'DELETE';
}

I keep it simple to start with and expand when needed - and only when needed. I cover the main HTTP verbs I will use and add more if needed.

I can refactor my contract to include how I want this to work.

/**
 * @property-read PendingRequest $request
 */
interface ClientContract
{
    public function send(Method $method, string $url, array $options = []): Response;
}

My clients’ send method should know the method used, the URL it is being sent to and any needed options. This is almost the same as the PendingRequest send method - other than using an Enum for the method, this is on purpose.

However, I do not add this to my client, as I may have multiple clients that want to send requests. So I create a concern/trait that I can add to each client, allowing it to send requests.

/**
 * @mixin ClientContract
 */
trait SendsRequests
{
    public function send(Method $method, string $url, array $options = []): Response
    {
        return $this->request->throw()->send(
            method: $method->value,
            url: $url,
            options: $options,
        );
    }
}

This standardizes how I send API requests and forces them to throw exceptions automatically. I can now add this behavior to my client itself, making it cleaner and more minimal.

final class Client implements ClientContract
{
    use SendsRequests;

    public function __construct(
        private readonly PendingRequest $request,
    ) {}
}

From here, I start to scope out resources and what I want a resource to be responsible for. It is all about the object design at this point. For me, a resource is an endpoint, an external resource available through the HTTP transport layer. It doesn’t need much more than that.

As usual, I create a contract/interface that I want all my resources to follow, meaning that I have predictable code.

/**
 * @property-read ClientContract $client
 */
interface ResourceContract
{
    public function client(): ClientContract;
}

We want our resources to be able to access the client itself through a getter method. We add the client as a docblock property as well.

Now we can create our first resource. We will focus on Issues as it is quite an exciting endpoint. Let’s start by creating the class and expanding on it.

final class IssuesResource implements ResourceContract
{
    use CanAccessClient;
}

I have created a new trait/concern here called CanAccessClient, as all of our resources, no matter the API, will want to access its parent client. I have also moved the constructor to this trait/concern - I accidentally discovered this works and loved it. I am still determining if I will always do this or keep it there, but it keeps my resources clean and focused - so I will keep it for now. I would love to hear your thoughts on this, though!

/**
 * @mixin ResourceContract
 */
trait CanAccessClient
{
    public function __construct(
        private readonly ClientContract $client,
    ) {}

    public function client(): ClientContract
    {
        return $this->client;
    }
}

Now that we have a resource, we can let our client know about it - and start looking toward the exciting part of integrations: requests.

final class Client implements ClientContract
{
    use SendsRequests;

    public function __construct(
        private readonly PendingRequest $request,
    ) {}

    public function issues(): IssuesResource
    {
        return new IssuesResource(
            client: $this,
        );
    }
}

This enables us to have a nice and clean API $client->issues()-> so we aren’t relying on magic methods or proxying anything - it is clean and discoverable for our IDE.

The first request we will want to be able to send is listing all issues for the authenticated user. The API endpoint for this is https://api.github.com/issues, which is quite simple. Let us now look at our requests and how we want to send them. Yes, you guessed it, we will need a contract/interface for this again.

/**
 * @property-read ResourceContract $resource
 */
interface RequestContract
{
    public function resource(): ResourceContract;
}

Out request will implement a concern/trait that will enable it to call the resource and pass the desired request back to the client.

/**
 * @mixin RequestContract
 */
trait HasResource
{
    public function __construct(
        private ResourceContract $resource,
    ) {}
    
    public function resource(): ResourceContract
    {
        return $this->resource;
    }
}

Finally, we can start thinking about the request we want to send! There is a lot of boilerplate to get to this stage. However, it will be worth it in the long run. We can fine-tune and make changes at any point of this chain without introducing breaking changes.

final class ListIssuesRequest implements RequestContract
{
    use HasResource;

    public function __invoke(): Response
    {
        return $this->resource()->client()->send(
            method: Method::GET,
            url: 'issues',
        );
    }
}

At this point, we can start looking at transforming the request should we want to. We have only set this up to return the response directly, but we can refactor this further should we need to. We make our request invokable so that we can call it directly. Our API now looks like the following:

$client->issues()->list();

We are working with the Illuminate Response to access the data from this point, so it has all the convenience methods we might want. However, this is only sometimes ideal. Sometimes we want to use something more usable as an object within our application. To do that, we need to look at transforming the response.

I am not going to go into too much here with transforming the response and what you can do, as I think that would make a great tutorial on its own. Let us know if you found this tutorial helpful or if you have any suggestions for improving this process.

What people say about me

Aaron Francis

Aaron Francis

Founder @ Try Hard Studies

Steve is one of the most thorough and thoughtful educators I've seen. He puts in a ton of effort and it clearly shows.
Alex Six

Alex Six

Head of Developer Relations @ Filament PHP

Steve is the teacher you wish you had in school. He’s informative, entertaining, and passionate about what he does. I’m always excited to see more of Steve’s content!
Brent Roose

Brent Roose

Developer Advocate @ jetBrains

To me, there's one word that comes to mind: 'passion'. There are only a handful of people with the same passion for programming as Steve.
Chris Miller

Chris Miller

Lead Developer @ MMS Marketing

Steve is a great developer with a wealth of knowledge that has contributed to many projects we have. His passion for API means we benefit from his aim for the best
Davor Minchorov

Davor Minchorov

Senior PHP Engineer @ Adeva

Steve is an awesome guy who knows a thing or two about APIs. I’ve learned so much from his content on his YouTube channel as well as his API video course.
Eric Barnes

Eric Barnes

Founder @ Laravel News

Steve is an awesome writer and communicator, he can take complex problems and communicate them in a way that anyone can understand.
Gary Clarke

Gary Clarke

YouTuber @ Gary Clarke Tech

Steve is highly engaging and an expert in what he does. I bookmark everything he publishes and refer back to it on a regular basis. The API king!
Aaron Francis

Aaron Francis

Founder @ Try Hard Studies

Steve is one of the most thorough and thoughtful educators I've seen. He puts in a ton of effort and it clearly shows.
Alex Six

Alex Six

Head of Developer Relations @ Filament PHP

Steve is the teacher you wish you had in school. He’s informative, entertaining, and passionate about what he does. I’m always excited to see more of Steve’s content!
Brent Roose

Brent Roose

Developer Advocate @ jetBrains

To me, there's one word that comes to mind: 'passion'. There are only a handful of people with the same passion for programming as Steve.
Chris Miller

Chris Miller

Lead Developer @ MMS Marketing

Steve is a great developer with a wealth of knowledge that has contributed to many projects we have. His passion for API means we benefit from his aim for the best
Davor Minchorov

Davor Minchorov

Senior PHP Engineer @ Adeva

Steve is an awesome guy who knows a thing or two about APIs. I’ve learned so much from his content on his YouTube channel as well as his API video course.
Eric Barnes

Eric Barnes

Founder @ Laravel News

Steve is an awesome writer and communicator, he can take complex problems and communicate them in a way that anyone can understand.
Gary Clarke

Gary Clarke

YouTuber @ Gary Clarke Tech

Steve is highly engaging and an expert in what he does. I bookmark everything he publishes and refer back to it on a regular basis. The API king!
Aaron Francis

Aaron Francis

Founder @ Try Hard Studies

Steve is one of the most thorough and thoughtful educators I've seen. He puts in a ton of effort and it clearly shows.
Alex Six

Alex Six

Head of Developer Relations @ Filament PHP

Steve is the teacher you wish you had in school. He’s informative, entertaining, and passionate about what he does. I’m always excited to see more of Steve’s content!
Brent Roose

Brent Roose

Developer Advocate @ jetBrains

To me, there's one word that comes to mind: 'passion'. There are only a handful of people with the same passion for programming as Steve.
Chris Miller

Chris Miller

Lead Developer @ MMS Marketing

Steve is a great developer with a wealth of knowledge that has contributed to many projects we have. His passion for API means we benefit from his aim for the best
Davor Minchorov

Davor Minchorov

Senior PHP Engineer @ Adeva

Steve is an awesome guy who knows a thing or two about APIs. I’ve learned so much from his content on his YouTube channel as well as his API video course.
Eric Barnes

Eric Barnes

Founder @ Laravel News

Steve is an awesome writer and communicator, he can take complex problems and communicate them in a way that anyone can understand.
Gary Clarke

Gary Clarke

YouTuber @ Gary Clarke Tech

Steve is highly engaging and an expert in what he does. I bookmark everything he publishes and refer back to it on a regular basis. The API king!
Aaron Francis

Aaron Francis

Founder @ Try Hard Studies

Steve is one of the most thorough and thoughtful educators I've seen. He puts in a ton of effort and it clearly shows.
Alex Six

Alex Six

Head of Developer Relations @ Filament PHP

Steve is the teacher you wish you had in school. He’s informative, entertaining, and passionate about what he does. I’m always excited to see more of Steve’s content!
Brent Roose

Brent Roose

Developer Advocate @ jetBrains

To me, there's one word that comes to mind: 'passion'. There are only a handful of people with the same passion for programming as Steve.
Chris Miller

Chris Miller

Lead Developer @ MMS Marketing

Steve is a great developer with a wealth of knowledge that has contributed to many projects we have. His passion for API means we benefit from his aim for the best
Davor Minchorov

Davor Minchorov

Senior PHP Engineer @ Adeva

Steve is an awesome guy who knows a thing or two about APIs. I’ve learned so much from his content on his YouTube channel as well as his API video course.
Eric Barnes

Eric Barnes

Founder @ Laravel News

Steve is an awesome writer and communicator, he can take complex problems and communicate them in a way that anyone can understand.
Gary Clarke

Gary Clarke

YouTuber @ Gary Clarke Tech

Steve is highly engaging and an expert in what he does. I bookmark everything he publishes and refer back to it on a regular basis. The API king!
Jack Ellis

Jack Ellis

Co-Founder @ Fathom Analytics

Steve is one of the top API experts in the world and has been teaching our community for years.
Laravel Jutsu

Laravel Jutsu

YouTuber @ Laravel Jutsu

Steve has a profound mastery of APIs and a public-serving teaching approach.
Luke Downing

Luke Downing

Educator @ Laracasts

Steve is a stream of knowledge. If you like clean, strict code and silky APIs, there’s nobody I’d sooner turn to for advice!
Sam Carré

Sam Carré

Head of Engineering @ Plannr CRM

Steve’s enthusiasm and positive attitude makes his educational content super easy to digest and makes learning new tools and languages really fun.
Peter Thomson

Peter Thomson

Chief Technology Officer @ Ice House Ventures

Steve is an absolute weapon. We came for the APIs but we stayed for the clean code, robust systems architecture and deep knowledge of Laravel conventions. Steve made our code faster, more stable and easier to maintain ourselves in the future.
Stephen Rees-Carter

Stephen Rees-Carter

Friendly Hacker @ Valorin Security

Steve is one of my favourite people. He has a huge passion for teaching developers about APIs and good coding practices.
Steven Tey

Steven Tey

Founder @ Dub.co

Steve brings knowledge and passion to the community, with easy to follow content that adds real value to any company that uses him.
Jack Ellis

Jack Ellis

Co-Founder @ Fathom Analytics

Steve is one of the top API experts in the world and has been teaching our community for years.
Laravel Jutsu

Laravel Jutsu

YouTuber @ Laravel Jutsu

Steve has a profound mastery of APIs and a public-serving teaching approach.
Luke Downing

Luke Downing

Educator @ Laracasts

Steve is a stream of knowledge. If you like clean, strict code and silky APIs, there’s nobody I’d sooner turn to for advice!
Sam Carré

Sam Carré

Head of Engineering @ Plannr CRM

Steve’s enthusiasm and positive attitude makes his educational content super easy to digest and makes learning new tools and languages really fun.
Peter Thomson

Peter Thomson

Chief Technology Officer @ Ice House Ventures

Steve is an absolute weapon. We came for the APIs but we stayed for the clean code, robust systems architecture and deep knowledge of Laravel conventions. Steve made our code faster, more stable and easier to maintain ourselves in the future.
Stephen Rees-Carter

Stephen Rees-Carter

Friendly Hacker @ Valorin Security

Steve is one of my favourite people. He has a huge passion for teaching developers about APIs and good coding practices.
Steven Tey

Steven Tey

Founder @ Dub.co

Steve brings knowledge and passion to the community, with easy to follow content that adds real value to any company that uses him.
Jack Ellis

Jack Ellis

Co-Founder @ Fathom Analytics

Steve is one of the top API experts in the world and has been teaching our community for years.
Laravel Jutsu

Laravel Jutsu

YouTuber @ Laravel Jutsu

Steve has a profound mastery of APIs and a public-serving teaching approach.
Luke Downing

Luke Downing

Educator @ Laracasts

Steve is a stream of knowledge. If you like clean, strict code and silky APIs, there’s nobody I’d sooner turn to for advice!
Sam Carré

Sam Carré

Head of Engineering @ Plannr CRM

Steve’s enthusiasm and positive attitude makes his educational content super easy to digest and makes learning new tools and languages really fun.
Peter Thomson

Peter Thomson

Chief Technology Officer @ Ice House Ventures

Steve is an absolute weapon. We came for the APIs but we stayed for the clean code, robust systems architecture and deep knowledge of Laravel conventions. Steve made our code faster, more stable and easier to maintain ourselves in the future.
Stephen Rees-Carter

Stephen Rees-Carter

Friendly Hacker @ Valorin Security

Steve is one of my favourite people. He has a huge passion for teaching developers about APIs and good coding practices.
Steven Tey

Steven Tey

Founder @ Dub.co

Steve brings knowledge and passion to the community, with easy to follow content that adds real value to any company that uses him.
Jack Ellis

Jack Ellis

Co-Founder @ Fathom Analytics

Steve is one of the top API experts in the world and has been teaching our community for years.
Laravel Jutsu

Laravel Jutsu

YouTuber @ Laravel Jutsu

Steve has a profound mastery of APIs and a public-serving teaching approach.
Luke Downing

Luke Downing

Educator @ Laracasts

Steve is a stream of knowledge. If you like clean, strict code and silky APIs, there’s nobody I’d sooner turn to for advice!
Sam Carré

Sam Carré

Head of Engineering @ Plannr CRM

Steve’s enthusiasm and positive attitude makes his educational content super easy to digest and makes learning new tools and languages really fun.
Peter Thomson

Peter Thomson

Chief Technology Officer @ Ice House Ventures

Steve is an absolute weapon. We came for the APIs but we stayed for the clean code, robust systems architecture and deep knowledge of Laravel conventions. Steve made our code faster, more stable and easier to maintain ourselves in the future.
Stephen Rees-Carter

Stephen Rees-Carter

Friendly Hacker @ Valorin Security

Steve is one of my favourite people. He has a huge passion for teaching developers about APIs and good coding practices.
Steven Tey

Steven Tey

Founder @ Dub.co

Steve brings knowledge and passion to the community, with easy to follow content that adds real value to any company that uses him.

© 2025 JustSteveKing. All rights reserved.