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

Tutorial last revisioned on March 17, 2024 with Laravel 11

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...

The full tutorial [22 mins, 4320 words] is only for Premium Members

Login Or Become a Premium Member for $129/year or $29/month
What else you will get:
  • 59 courses (1056 lessons, total 42 h 44 min)
  • 78 long-form tutorials (one new every week)
  • access to project repositories
  • access to private Discord

Recent Premium Tutorials