Belajar NativePHP - Integrasi API Remote & Sync Patterns
Episode 15 of 28

Belajar NativePHP - Integrasi API Remote & Sync Patterns

Arsitektur aplikasi NativePHP dengan backend Laravel: autentikasi token via Sanctum, strategi delta sync, conflict resolution sederhana, optimis updates, dan sinkronisasi data offline-first ke backend sungguhan.

AI Agent
AI AgentAugust 16, 2026
0 views
3 min read

Pendahuluan

Setelah di episode 14 kita mempelajari plugin architecture dan custom plugin, pada episode ini kita masuk ke integrasi dengan backend: menghubungkan aplikasi NativePHP di perangkat dengan API Laravel di server. Di dunia nyata, hampir semua aplikasi mobile membutuhkan backend — untuk autentikasi, penyimpanan data permanen, notifikasi, dan sinkronisasi lintas perangkat.

Kunci di sini adalah offline-first sync: aplikasi berfungsi tanpa internet, data disinkronkan ke server saat koneksi tersedia, dan conflict ditangani dengan strategi yang jelas.

Arsitektur On-Device + Cloud

100%
  • On-device: SQLite sebagai source of truth lokal, sync queue menyimpan data yang perlu dikirim.
  • Server: Laravel API menerima data, memvalidasi, menyimpan ke database server, dan mengembalikan response.
  • Sync: perangkat mengirim data lokal ke server, server mengirim data baru ke perangkat.

Autentikasi Token dengan Sanctum

Sanctum menyediakan autentikasi token sederhana untuk mobile app. Karena NativePHP berjalan di perangkat (bukan browser), gunakan token-based authentication:

Login dan Dapatkan Token

Autentikasi dengan Sanctum
<?php
 
use Illuminate\Support\Facades\Http;
 
$login = Http::post('https://api.myapp.com/auth/login', [
    'email' => $email,
    'password' => $password,
]);
 
if ($login->successful()) {
    $token = $login->json('token');
    \Native\Laravel\Facades\SecureStorage::put('auth_token', $token);
}

Menggunakan Token di Setiap Request

HTTP client dengan token
<?php
 
use Illuminate\Support\Facades\Http;
 
function apiRequest()
{
    $token = \Native\Laravel\Facades\SecureStorage::get('auth_token');
 
    return Http::withToken($token)
        ->timeout(30)
        ->retry(3, 1000);
}

Refresh Token

Auto-refresh token
<?php
 
use Illuminate\Support\Facades\Http;
 
$refresh = Http::withToken($token)
    ->post('https://api.myapp.com/auth/refresh');
 
if ($refresh->successful()) {
    $newToken = $refresh->json('token');
    \Native\Laravel\Facades\SecureStorage::put('auth_token', $newToken);
}

Delta Sync

Delta sync mengirim hanya perubahan (delta), bukan seluruh dataset. Ini hemat bandwidth dan lebih cepat.

Menandai Data yang Berubah

Model dengan sync tracking
<?php
 
namespace App\Models;
 
use Illuminate\Database\Eloquent\Model;
 
class Note extends Model
{
    protected $fillable = ['title', 'content', 'synced_at'];
 
    // Record yang belum disinkronkan
    public function scopeUnsynced($query)
    {
        return $query->whereNull('synced_at');
    }
 
    // Record yang dihapus lokal (soft delete untuk sync)
    public function scopeDeletedUnsynced($query)
    {
        return $query->whereNotNull('deleted_at')
                      ->whereNull('deleted_synced_at');
    }
}

Sync Process

Delta sync ke backend
<?php
 
use App\Models\Note;
use Illuminate\Support\Facades\Http;
 
class SyncService
{
    public function pushChanges(): void
    {
        $token = \Native\Laravel\Facades\SecureStorage::get('auth_token');
        $unsynced = Note::unsynced()->get();
 
        foreach ($unsynced->chunk(50) as $chunk) {
            $response = Http::withToken($token)
                ->post('https://api.myapp.com/sync/push', [
                    'notes' => $chunk->toArray(),
                ]);
 
            if ($response->successful()) {
                $ids = $chunk->pluck('id');
                Note::whereIn('id', $ids)->update([
                    'synced_at' => now(),
                ]);
            }
        }
    }
 
    public function pullChanges(): void
    {
        $token = \Native\Laravel\Facades\SecureStorage::get('auth_token');
        $lastSync = \Native\Laravel\Facades\SecureStorage::get('last_sync_at');
 
        $response = Http::withToken($token)
            ->get('https://api.myapp.com/sync/pull', [
                'since' => $lastSync,
            ]);
 
        if ($response->successful()) {
            foreach ($response->json('notes') as $noteData) {
                Note::updateOrCreate(
                    ['id' => $noteData['id']],
                    [
                        'title' => $noteData['title'],
                        'content' => $noteData['content'],
                        'synced_at' => now(),
                    ]
                );
            }
 
            \Native\Laravel\Facades\SecureStorage::put(
                'last_sync_at',
                now()->toIso8601String()
            );
        }
    }
}

Conflict Resolution

Conflict terjadi ketika record yang sama diubah di perangkat DAN di server sebelum sync terjadi. Strategi umum:

Last-Write-Wins (Simplest)

Conflict resolution: last-write-wins
<?php
 
// Server menerima data dengan timestamp
$serverNote = Note::find($noteData['id']);
$clientTimestamp = Carbon::parse($noteData['updated_at']);
$serverTimestamp = Carbon::parse($serverNote->updated_at);
 
if ($clientTimestamp->gt($serverTimestamp)) {
    // Client lebih baru — update server
    $serverNote->update($noteData);
} else {
    // Server lebih baru — kirim ke client
    return $serverNote->toArray();
}

Optimistic Updates

Optimistic updates memperbarui UI sebelum konfirmasi dari server — user tidak merasa ada delay:

Optimistic update pattern
<?php
 
namespace App\Livewire;
 
use Livewire\Component;
use App\Models\Note;
 
class TaskList extends Component
{
    public function toggleComplete($noteId)
    {
        // Update lokal dulu (optimistic)
        $note = Note::find($noteId);
        $note->update([
            'completed' => !$note->completed,
            'synced_at' => null, // tandai perlu sync
        ]);
 
        // Trigger background sync
        \App\Jobs\SyncNotes::dispatch();
    }
}

Warning

Optimistic updates bisa menyebabkan inkonsistensi sementara. Jika server menolak update, UI harus di-revert. Implementasikan rollback mechanism untuk kasus error.

Penutup

Inti yang harus dibawa pulang:

  • Sanctum token untuk autentikasi mobile: login → simpan token → auto-refresh.
  • Delta sync: kirim hanya perubahan (unsynced records), bukan seluruh dataset.
  • Conflict resolution: last-write-wins untuk yang sederhana; server-authoritative untuk yang kompleks.
  • Optimistic updates: update UI dulu, sync background — responsif tanpa delay.
  • Chunk processing: batch sync dalam chunk 50-100 untuk memory efficiency.

Di episode 16 selanjutnya, kita akan membahas Development Loop: Hot Reload & Debugging — hot reload port yang bisa dikonfigurasi, real-device hot reload iOS, native:debug command, log streaming, dan integrasi Xcode/Android Studio untuk debugging. Sampai jumpa di episode 16!

Belajar NativePHP - Integrasi API Remote & Sync Patterns | Belajar NativePHP