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 -mphp artisan make:model StackOverflowTag -mphp 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...