Skip to main content

Black Friday 2025! Only until December 1st: coupon FRIDAY25 for 40% off Yearly/Lifetime membership!

Read more here
Premium Members Only
Join to unlock this tutorial and all of our courses.
Tutorial Premium Tutorial

Laravel: Using Simple External 3rd Party APIs - Four Examples

December 05, 2023
22 min read

Tutorial last revisioned on June 12, 2025 with Laravel 12

Many Laravel developer jobs require not only creating APIs but also interacting with other 3rd-party APIs. In this lengthy tutorial, we will show four examples of such APIs:

  • Stackoverflow API (public)
  • Currency Rate API (public)
  • Two Weather APIs (API key required)
  • OpenAI (API key required)

Let's go, one by one.


1. StackOverflow API: Get Questions by Query

For the first project in this course, we will use the public API for Stackoverflow to get the latest ten questions and save them in the DB. We will create an Artisan command and output how many new questions were created for this.

Note that public APIs usually have very low rate limits.


1.1. DB Structure

Before creating Migrations with Models, we must know what we will save. First, we must check what result the response will give. We will use the advanced search API for which docs are found here.

For this example, we will keep it simple, and for questions will save title, link, creation_data, and is_answered. Also, we will save the name of the tags for questions.

php artisan make:model StackOverflowQuestion -m
php artisan make:model StackOverflowTag -m
php artisan make:migration "create stack overflow question tags table"

database/migrations/xxx_create_stack_overflow_questions_table.php:

public function up(): void
{
Schema::create('stack_overflow_questions', function (Blueprint $table) {
$table->id();
$table->string('title');
$table->string('link');
$table->dateTime('creation_date');
$table->boolean('is_answered')->default(false);
$table->timestamps();
});
}

app/Models/StackOverflowQuestion:

use Illuminate\Database\Eloquent\Relations\BelongsToMany;
 
class StackOverflowQuestion extends Model
{
protected $fillable = [
'title',
'link',
'creation_date',
'is_answered',
];
 
public function tags(): BelongsToMany
{
return $this->belongsToMany(StackOverflowTag::class, 'stack_overflow_question_tags');
}
}

database/migrations/xxx_create_stack_overflow_tags_table.php:

public function up(): void
{
Schema::create('stack_overflow_questions', function (Blueprint $table) {
$table->id();
$table->string('name');
$table->timestamps();
});
}

app/Models/StackOverflowTag:

class StackOverflowTag extends Model
{
protected $fillable = [
'name',
];
}

database/migrations/xxx_create_stack_overflow_question_tags_table.php:

use App\Models\StackOverflowTag;
use App\Models\StackOverflowQuestion;
 
return new class extends Migration {
public function up(): void
{
Schema::create('stack_overflow_question_tags', function (Blueprint $table) {
$table->id();
$table->foreignIdFor(StackOverflowQuestion::class)->constrained();
$table->foreignIdFor(StackOverflowTag::class)->constrained();
$table->timestamps();
});
}
}

1.2. Artisan Command

Now let's create and artisan command.

php artisan make:command StackoverflowSyncPostsCommand

app/Console/Commands/StackoverflowSyncPostsCommand.php:

class StackoverflowSyncPostsCommand extends Command
{
protected $signature = 'stackoverflow:sync-posts';
 
protected $description = 'Command description';
 
public function handle(): void
{
 
}
}

For making an HTTP request, we will use Laravel's wrapper around Guzzle. And to the request based on the API docs we must pass GET Request query parameters.

app/Console/Commands/StackoverflowSyncPostsCommand.php:

use Illuminate\Support\Facades\Http;
 
class StackoverflowSyncPostsCommand extends Command
{
protected $signature = 'stackoverflow:sync-posts';
 
protected $description = 'Command description';
 
public function handle(): void
{
$response = Http::get('https://api.stackexchange.com/2.3/search/advanced', [
'order' => 'desc',
'sort' => 'creation',
'tagged' => 'laravel',
'site' => 'stackoverflow',
'pagesize' => '10',
]);
}
}

Next, we will create a new private method where the whole logic for creating questions and tags will be.

app/Console/Commands/StackoverflowSyncPostsCommand.php:

use Illuminate\Support\Carbon;
use App\Models\StackOverflowTag;
use Illuminate\Http\Client\Response;
use App\Models\StackOverflowQuestion;
use GuzzleHttp\Promise\PromiseInterface;
 
class StackoverflowSyncPostsCommand extends Command
{
protected $signature = 'stackoverflow:sync-posts';
 
protected $description = 'Command description';
 
public function handle(): void
{
$response = Http::get('https://api.stackexchange.com/2.3/search/advanced', [
'order' => 'desc',
'sort' => 'creation',
'tagged' => 'laravel',
'site' => 'stackoverflow',
'pagesize' => '10',
]);
 
$this->saveQuestions($response);
}
 
private function saveQuestions(PromiseInterface|Response $response): int
{
$questions = json_decode($response->body())->items;
$newQuestions = 0;
 
foreach ($questions as $question) {
$questionTags = [];
foreach ($question->tags as $tag) {
$questionTags[] = StackOverflowTag::firstOrCreate(['name' => $tag])->id;
}
 
$savedQuestion = StackOverflowQuestion::updateOrCreate(
[
'link' => $question->link,
],
[
'title' => $question->title,
'link' => $question->link,
'creation_date' => Carbon::createFromTimestamp($question->creation_date),
'is_answered' => $question->is_answered,
]
);
 
if ($savedQuestion->wasRecentlyCreated) {
$newQuestions++;
}
 
if ($savedQuestion->tags()->count() === 0) {
$savedQuestion->tags()->attach($questionTags);
}
}
 
return $newQuestions;
}
}

First, because the response from this API is always a JSON, we need to decode it grab the items key.

Then, we do the usual Laravel logic in the foreach loop. We get or create the tag based on name using the firstOrCreate method.

And then, using the updateOrCreate method, we create a new question based on the link.

Lastly, if the question is created, we increase the $newQuestions counter, attach the tags to questions, and return how many new questions were created.

Now, where we call the saveQuestions private method in the handle method, we can assign it to a variable and use this variable to show the output of the command.

app/Console/Commands/StackoverflowSyncPostsCommand.php:

class StackoverflowSyncPostsCommand extends Command
{
protected $signature = 'stackoverflow:sync-posts';
 
protected $description = 'Command description';
 
public function handle(): void
{
$response = Http::get('https://api.stackexchange.com/2.3/search/advanced', [
'order' => 'desc',
'sort' => 'creation',
'tagged' => 'laravel',
'site' => 'stackoverflow',
'pagesize' => '10',
]);
 
$this->saveQuestions($response);
 
$newQuestions = $this->saveQuestions($response);
 
$this->components->info('Added new questions: ' . $newQuestions);
}
 
// ...
}


2. Another Public API: Currency Rate

For the second example of using public API, we will create a simple application showing the USD currency rate.

For the API, we will use...

Premium Members Only

This advanced tutorial is available exclusively to Laravel Daily Premium members.

Premium membership includes:

Access to all premium tutorials
Video and Text Courses
Private Discord Channel

Comments & Discussion

BC
Brandon C ✓ Link copied!

Great tutorial, I would like to see good practice for error handling, not allowed when you Http. Or would that be better handled in the method calling the api?

S
Sjoerd24 ✓ Link copied!

great tutorial! i am very interested in the openAI integration. That looks easier then I thought. I would like to integrate this into filament, would be ideal if chatgpt could answer questions on the basis of supplied pdfs and stuff. What a future we live in that this is even possible! not enough hours in a day to make everything though. :p

O
Oleksii ✓ Link copied!

would be good to see the ways how to correctly structurize more complex 3rd party api's or when there are few api used in laravel, for example using service class or service provider

We'd Love Your Feedback

Tell us what you like or what we can improve

Feel free to share anything you like or dislike about this page or the platform in general.