This repository contains a Laravel application designed to fetch, process, and store user and post data from external APIs (DummyJSON or JSONPlaceholder) efficiently.
Follow these steps to set up the project locally:
-
Clone the repository
git clone https://github.com/MHJanny/laravel-external-data.git cd laravel-external-data -
Install Dependencies
# Install PHP dependencies composer install # Install Node.js dependencies npm install # Compile front-end assets npm run build
-
Environment Configuration
Copy the example environment file.
cp .env.example .env
-
Generate Application Key
php artisan key:generate
-
Run Migrations
Create the necessary database tables.
php artisan migrate
-
Run the Import Command
Execute the custom Artisan command to fetch and import data.
php artisan app:import-data
-
Start the Application
php artisan serve
To handle potentially large datasets and ensure system stability, the following strategies were implemented:
-
Generators for Memory Efficiency:
- Instead of loading all API data into memory at once, I utilized PHP Generators (
yield). TheDummyJsonServiceandJsonPlaceholderServicefetches data in pages (pagination) and yields chunks of data. This allows the application to process millions of records with constant low memory usage.
- Instead of loading all API data into memory at once, I utilized PHP Generators (
-
Batch Processing & Database Upserts:
- Data is processed in batches (chunks).
- I used
User::upsert()andPost::upsert()instead of individualcreateorupdatecalls. This significantly reduces database round-trips and improves write performance. upsertalso handles idempotency, ensuring that re-running the command updates existing records rather than creating duplicates.
-
Resilient API Communication:
- The HTTP client is configured with retry logic (3 retries with exponential backoff) and timeouts (connect and request) to handle network instability or API rate limiting gracefully.
-
Abstraction & Extensibility:
- A
DataSourceInterfacewas created to define the contract for data fetching. - The
AppServiceProviderbinds the concrete implementation based on configuration. This makes it trivial to swap data sources (e.g., switching from DummyJSON to JSONPlaceholder) without changing the core import logic.
- A
- Challenge: Fetching thousands of records at once can easily exceed PHP's memory limit.
- Solution: Implemented pagination in the API service combined with PHP Generators. The
ImportDataCommanditerates over the generator, processing one batch at a time, ensuring memory usage remains stable regardless of the dataset size.
- Challenge: External APIs can fail intermittently or block requests if sent too quickly.
- Solution: Used Laravel's HTTP Client
retry()method to automatically retry failed requests. Addedsleepintervals between retries to respect potential rate limits.
- Challenge: Running the import command multiple times could result in duplicate data or outdated records.
- Solution: Utilized
upsert(Update or Insert) based on the uniqueexternal_id. This ensures that the local database always reflects the latest state of the external source without duplication errors.