Contoh Integrasi API
Halaman ini menyediakan contoh praktis integrasi dengan API Laravel Nusa dari berbagai platform dan bahasa pemrograman.
Integrasi JavaScript/Frontend
JavaScript Murni
js
class NusaAPI {
constructor(baseUrl = '/nusa') {
this.baseUrl = baseUrl;
}
async request(endpoint, options = {}) {
const url = `${this.baseUrl}${endpoint}`;
const response = await fetch(url, {
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
...options.headers
},
...options
});
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
return response.json();
}
// Metode Provinsi
async getProvinces(params = {}) {
const query = new URLSearchParams(params);
return this.request(`/provinces?${query}`);
}
async getProvince(code) {
return this.request(`/provinces/${code}`);
}
// Metode Kabupaten/Kota
async getRegencies(params = {}) {
const query = new URLSearchParams(params);
return this.request(`/regencies?${query}`);
}
async getRegenciesByProvince(provinceCode, params = {}) {
const query = new URLSearchParams(params);
return this.request(`/provinces/${provinceCode}/regencies?${query}`);
}
// Metode Kecamatan
async getDistrictsByRegency(regencyCode, params = {}) {
const query = new URLSearchParams(params);
return this.request(`/regencies/${regencyCode}/districts?${query}`);
}
// Metode Desa/Kelurahan
async getVillagesByDistrict(districtCode, params = {}) {
const query = new URLSearchParams(params);
return this.request(`/districts/${districtCode}/villages?${query}`);
}
// Metode Pencarian
async searchProvinces(query) {
return this.getProvinces({ search: query });
}
async searchRegencies(query) {
return this.getRegencies({ search: query });
}
}
// Penggunaan
const nusa = new NusaAPI();
// Dapatkan semua provinsi
const provinces = await nusa.getProvinces();
console.log(provinces.data);
// Cari provinsi Jawa
const javaProvinces = await nusa.searchProvinces('jawa');
console.log(javaProvinces.data);
// Dapatkan kabupaten/kota di Jawa Tengah
const regencies = await nusa.getRegenciesByProvince('33');
console.log(regencies.data);
React Hook
jsx
import { useState, useEffect } from 'react';
// Hook kustom untuk Nusa API
function useNusaAPI() {
const [loading, setLoading] = useState(false);
const [error, setError] = useState(null);
const request = async (endpoint, options = {}) => {
setLoading(true);
setError(null);
try {
const response = await fetch(`/nusa${endpoint}`, {
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
...options.headers
},
...options
});
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const data = await response.json();
return data;
} catch (err) {
setError(err.message);
throw err;
} finally {
setLoading(false);
}
};
return { request, loading, error };
}
// Komponen formulir alamat
function AddressForm() {
const { request, loading, error } = useNusaAPI();
const [provinces, setProvinces] = useState([]);
const [regencies, setRegencies] = useState([]);
const [districts, setDistricts] = useState([]);
const [villages, setVillages] = useState([]);
const [selectedProvince, setSelectedProvince] = useState('');
const [selectedRegency, setSelectedRegency] = useState('');
const [selectedDistrict, setSelectedDistrict] = useState('');
const [selectedVillage, setSelectedVillage] = useState('');
// Muat provinsi saat komponen dimuat
useEffect(() => {
const loadProvinces = async () => {
try {
const response = await request('/provinces');
setProvinces(response.data);
} catch (err) {
console.error('Gagal memuat provinsi:', err);
}
};
loadProvinces();
}, []);
// Muat kabupaten/kota saat provinsi berubah
useEffect(() => {
if (selectedProvince) {
const loadRegencies = async () => {
try {
const response = await request(`/provinces/${selectedProvince}/regencies`);
setRegencies(response.data);
setDistricts([]);
setVillages([]);
setSelectedRegency('');
setSelectedDistrict('');
setSelectedVillage('');
} catch (err) {
console.error('Gagal memuat kabupaten/kota:', err);
}
};
loadRegencies();
}
}, [selectedProvince]);
// Muat kecamatan saat kabupaten/kota berubah
useEffect(() => {
if (selectedRegency) {
const loadDistricts = async () => {
try {
const response = await request(`/regencies/${selectedRegency}/districts`);
setDistricts(response.data);
setVillages([]);
setSelectedDistrict('');
setSelectedVillage('');
} catch (err) {
console.error('Gagal memuat kecamatan:', err);
}
};
loadDistricts();
}
}, [selectedRegency]);
// Muat desa/kelurahan saat kecamatan berubah
useEffect(() => {
if (selectedDistrict) {
const loadVillages = async () => {
try {
const response = await request(`/districts/${selectedDistrict}/villages`);
setVillages(response.data);
setSelectedVillage('');
} catch (err) {
console.error('Gagal memuat desa/kelurahan:', err);
}
};
loadVillages();
}
}, [selectedDistrict]);
return (
<form>
{error && <div className="error">Error: {error}</div>}
<div>
<label>Provinsi:</label>
<select
value={selectedProvince}
onChange={(e) => setSelectedProvince(e.target.value)}
disabled={loading}
>
<option value="">Pilih Provinsi</option>
{provinces.map(province => (
<option key={province.code} value={province.code}>
{province.name}
</option>
))}
</select>
</div>
<div>
<label>Kabupaten/Kota:</label>
<select
value={selectedRegency}
onChange={(e) => setSelectedRegency(e.target.value)}
disabled={loading || !selectedProvince}
>
<option value="">Pilih Kabupaten/Kota</option>
{regencies.map(regency => (
<option key={regency.code} value={regency.code}>
{regency.name}
</option>
))}
</select>
</div>
<div>
<label>Kecamatan:</label>
<select
value={selectedDistrict}
onChange={(e) => setSelectedDistrict(e.target.value)}
disabled={loading || !selectedRegency}
>
<option value="">Pilih Kecamatan</option>
{districts.map(district => (
<option key={district.code} value={district.code}>
{district.name}
</option>
))}
</select>
</div>
<div>
<label>Desa/Kelurahan:</label>
<select
value={selectedVillage}
onChange={(e) => setSelectedVillage(e.target.value)}
disabled={loading || !selectedDistrict}
>
<option value="">Pilih Desa/Kelurahan</option>
{villages.map(village => (
<option key={village.code} value={village.code}>
{village.name} {village.postal_code && `(${village.postal_code})`}
</option>
))}
</select>
</div>
{loading && <div>Memuat...</div>}
</form>
);
}
export default AddressForm;
Integrasi PHP
Laravel HTTP Client
php
namespace App\Services;
use Illuminate\Http\Client\Response;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Cache;
class NusaAPIService
{
private string $baseUrl;
private int $timeout;
private int $cacheTimeout;
public function __construct()
{
$this->baseUrl = config('app.url') . '/nusa';
$this->timeout = 30;
$this->cacheTimeout = 3600; // 1 jam
}
private function request(string $endpoint, array $params = []): array
{
$response = Http::timeout($this->timeout)
->get($this->baseUrl . $endpoint, $params);
if ($response->failed()) {
throw new \Exception("Permintaan API gagal: {$response->status()}");
}
return $response->json();
}
public function getProvinces(array $params = []): array
{
$cacheKey = 'nusa.provinces.' . md5(serialize($params));
return Cache::remember($cacheKey, $this->cacheTimeout, function () use ($params) {
return $this->request('/provinces', $params);
});
}
public function getProvince(string $code): array
{
$cacheKey = "nusa.province.{$code}";
return Cache::remember($cacheKey, $this->cacheTimeout, function () use ($code) {
return $this->request("/provinces/{$code}");
});
}
public function getRegenciesByProvince(string $provinceCode, array $params = []): array
{
$cacheKey = "nusa.regencies.{$provinceCode}." . md5(serialize($params));
return Cache::remember($cacheKey, $this->cacheTimeout, function () use ($provinceCode, $params) {
return $this->request("/provinces/{$provinceCode}/regencies", $params);
});
}
public function getDistrictsByRegency(string $regencyCode, array $params = []): array
{
$cacheKey = "nusa.districts.{$regencyCode}." . md5(serialize($params));
return Cache::remember($cacheKey, $this->cacheTimeout, function () use ($regencyCode, $params) {
return $this->request("/regencies/{$regencyCode}/districts", $params);
});
}
public function getVillagesByDistrict(string $districtCode, array $params = []): array
{
$cacheKey = "nusa.villages.{$districtCode}." . md5(serialize($params));
return Cache::remember($cacheKey, $this->cacheTimeout, function () use ($districtCode, $params) {
return $this->request("/districts/{$districtCode}/villages", $params);
});
}
public function searchProvinces(string $query): array
{
return $this->getProvinces(['search' => $query]);
}
public function searchRegencies(string $query): array
{
return $this->request('/regencies', ['search' => $query]);
}
public function getFullAddressHierarchy(string $villageCode): array
{
$village = $this->request("/villages/{$villageCode}");
$villageData = $village['data'];
$district = $this->request("/districts/{$villageData['district_code']}");
$regency = $this->request("/regencies/{$villageData['regency_code']}");
$province = $this->request("/provinces/{$villageData['province_code']}");
return [
'village' => $villageData,
'district' => $district['data'],
'regency' => $regency['data'],
'province' => $province['data'],
'full_address' => implode(', ', [
$villageData['name'],
$district['data']['name'],
$regency['data']['name'],
$province['data']['name'],
$villageData['postal_code'] ?? ''
])
];
}
}
// Penggunaan di controller
class AddressController extends Controller
{
private NusaAPIService $nusaAPI;
public function __construct(NusaAPIService $nusaAPI)
{
$this->nusaAPI = $nusaAPI;
}
public function getProvinces()
{
try {
$provinces = $this->nusaAPI->getProvinces();
return response()->json($provinces['data']);
} catch (\Exception $e) {
return response()->json(['error' => $e->getMessage()], 500);
}
}
public function getRegencies(Request $request)
{
$request->validate([
'province_code' => 'required|string|size:2'
]);
try {
$regencies = $this->nusaAPI->getRegenciesByProvince(
$request->province_code
);
return response()->json($regencies['data']);
} catch (\Exception $e) {
return response()->json(['error' => $e->getMessage()], 500);
}
}
}
Integrasi Python
Menggunakan Pustaka Requests
python
import requests
from typing import Dict, List, Optional
import time
class NusaAPI:
def __init__(self, base_url: str = "https://your-app.com/nusa", timeout: int = 30):
self.base_url = base_url.rstrip('/')
self.timeout = timeout
self.session = requests.Session()
self.session.headers.update({
'Accept': 'application/json',
'Content-Type': 'application/json'
})
def _request(self, endpoint: str, params: Optional[Dict] = None) -> Dict:
"""Make a request to the API"""
url = f"{self.base_url}{endpoint}"
try:
response = self.session.get(url, params=params, timeout=self.timeout)
response.raise_for_status()
return response.json()
except requests.exceptions.RequestException as e:
raise Exception(f"Permintaan API gagal: {e}")
def get_provinces(self, params: Optional[Dict] = None) -> Dict:
"""Get all provinces"""
return self._request('/provinces', params)
def get_province(self, code: str) -> Dict:
"""Get specific province by code"""
return self._request(f'/provinces/{code}')
def get_regencies_by_province(self, province_code: str, params: Optional[Dict] = None) -> Dict:
"""Get regencies in a province"""
return self._request(f'/provinces/{province_code}/regencies', params)
def get_districts_by_regency(self, regency_code: str, params: Optional[Dict] = None) -> Dict:
"""Get districts in a regency"""
return self._request(f'/regencies/{regency_code}/districts', params)
def get_villages_by_district(self, district_code: str, params: Optional[Dict] = None) -> Dict:
"""Get villages in a district"""
return self._request(f'/districts/{district_code}/villages', params)
def search_provinces(self, query: str) -> Dict:
"""Search provinces by name or code"""
return self.get_provinces({'search': query})
def search_regencies(self, query: str) -> Dict:
"""Search regencies by name or code"""
return self._request('/regencies', {'search': query})
def get_full_address_hierarchy(self, village_code: str) -> Dict:
"""Get complete address hierarchy for a village"""
village = self._request(f'/villages/{village_code}')
village_data = village['data']
district = self._request(f"/districts/{village_data['district_code']}")
regency = self._request(f"/regencies/{village_data['regency_code']}")
province = self._request(f"/provinces/{village_data['province_code']}")
return {
'village': village_data,
'district': district['data'],
'regency': regency['data'],
'province': province['data'],
'full_address': ', '.join(filter(None, [
village_data['name'],
district['data']['name'],
regency['data']['name'],
province['data']['name'],
village_data.get('postal_code', '')
]))
}
# Contoh penggunaan
def main():
nusa = NusaAPI()
# Dapatkan semua provinsi
provinces = nusa.get_provinces()
print(f"Ditemukan {len(provinces['data'])} provinsi")
# Cari provinsi Jawa
java_provinces = nusa.search_provinces("jawa")
for province in java_provinces['data']:
print(f"- {province['name']} ({province['code']})")
# Dapatkan kabupaten/kota di Jawa Tengah
regencies = nusa.get_regencies_by_province("33")
print(f"Jawa Tengah memiliki {len(regencies['data'])} kabupaten/kota")
# Dapatkan hierarki alamat lengkap
address = nusa.get_full_address_hierarchy("3375011002")
print(f"Alamat lengkap: {address['full_address']}")
if __name__ == "__main__":
main()
Integrasi Django
python
# services.py
from django.conf import settings
from django.core.cache import cache
import requests
class NusaAPIService:
def __init__(self):
self.base_url = getattr(settings, 'NUSA_API_URL', 'https://your-app.com/nusa')
self.timeout = getattr(settings, 'NUSA_API_TIMEOUT', 30)
self.cache_timeout = getattr(settings, 'NUSA_CACHE_TIMEOUT', 3600)
def _get_cached_or_fetch(self, cache_key: str, url: str, params=None):
"""Get from cache or fetch from API"""
cached_data = cache.get(cache_key)
if cached_data:
return cached_data
response = requests.get(url, params=params, timeout=self.timeout)
response.raise_for_status()
data = response.json()
cache.set(cache_key, data, self.cache_timeout)
return data
def get_provinces(self):
cache_key = 'nusa_provinces'
url = f'{self.base_url}/provinces'
return self._get_cached_or_fetch(cache_key, url)
def get_regencies_by_province(self, province_code: str):
cache_key = f'nusa_regencies_{province_code}'
url = f'{self.base_url}/provinces/{province_code}/regencies'
return self._get_cached_or_fetch(cache_key, url)
# views.py
from django.http import JsonResponse
from django.views import View
from .services import NusaAPIService
class ProvinceListView(View):
def get(self, request):
try:
nusa_service = NusaAPIService()
provinces = nusa_service.get_provinces()
return JsonResponse(provinces['data'], safe=False)
except Exception as e:
return JsonResponse({'error': str(e)}, status=500)
class RegencyListView(View):
def get(self, request, province_code):
try:
nusa_service = NusaAPIService()
regencies = nusa_service.get_regencies_by_province(province_code)
return JsonResponse(regencies['data'], safe=False)
except Exception as e:
return JsonResponse({'error': str(e)}, status=500)
Integrasi Aplikasi Seluler
Flutter/Dart
dart
import 'dart:convert';
import 'package:http/http.dart' as http;
class NusaAPI {
final String baseUrl;
final Duration timeout;
NusaAPI({
this.baseUrl = 'https://your-app.com/nusa',
this.timeout = const Duration(seconds: 30),
});
Future<Map<String, dynamic>> _request(String endpoint, [Map<String, String>? params]) async {
final uri = Uri.parse('$baseUrl$endpoint').replace(queryParameters: params);
try {
final response = await http.get(
uri,
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
},
).timeout(timeout);
if (response.statusCode == 200) {
return json.decode(response.body);
} else {
throw Exception('HTTP ${response.statusCode}: ${response.body}');
}
} catch (e) {
throw Exception('Permintaan API gagal: $e');
}
}
Future<List<dynamic>> getProvinces({String? search}) async {
final params = search != null ? {'search': search} : null;
final response = await _request('/provinces', params);
return response['data'];
}
Future<Map<String, dynamic>> getProvince(String code) async {
final response = await _request('/provinces/$code');
return response['data'];
}
Future<List<dynamic>> getRegenciesByProvince(String provinceCode) async {
final response = await _request('/provinces/$provinceCode/regencies');
return response['data'];
}
Future<List<dynamic>> getDistrictsByRegency(String regencyCode) async {
final response = await _request('/regencies/$regencyCode/districts');
return response['data'];
}
Future<List<dynamic>> getVillagesByDistrict(String districtCode) async {
final response = await _request('/districts/$districtCode/villages');
return response['data'];
}
}
// Penggunaan di widget Flutter
class AddressFormWidget extends StatefulWidget {
@override
_AddressFormWidgetState createState() => _AddressFormWidgetState();
}
class _AddressFormWidgetState extends State<AddressFormWidget> {
final NusaAPI _nusaAPI = NusaAPI();
List<dynamic> provinces = [];
List<dynamic> regencies = [];
List<dynamic> districts = [];
List<dynamic> villages = [];
String? selectedProvince;
String? selectedRegency;
String? selectedDistrict;
String? selectedVillage;
bool isLoading = false;
@override
void initState() {
super.initState();
_loadProvinces();
}
Future<void> _loadProvinces() async {
setState(() => isLoading = true);
try {
final data = await _nusaAPI.getProvinces();
setState(() => provinces = data);
} catch (e) {
print('Gagal memuat provinsi: $e');
} finally {
setState(() => isLoading = false);
}
}
Future<void> _loadRegencies(String provinceCode) async {
setState(() => isLoading = true);
try {
final data = await _nusaAPI.getRegenciesByProvince(provinceCode);
setState(() {
regencies = data;
districts = [];
villages = [];
selectedRegency = null;
selectedDistrict = null;
selectedVillage = null;
});
} catch (e) {
print('Gagal memuat kabupaten/kota: $e');
} finally {
setState(() => isLoading = false);
}
}
@override
Widget build(BuildContext context) {
return Column(
children: [
DropdownButtonFormField<String>(
value: selectedProvince,
decoration: InputDecoration(labelText: 'Provinsi'),
items: provinces.map<DropdownMenuItem<String>>((province) {
return DropdownMenuItem<String>(
value: province['code'],
child: Text(province['name']),
);
}).toList(),
onChanged: (value) {
setState(() => selectedProvince = value);
if (value != null) _loadRegencies(value);
},
),
// Tambahkan dropdown serupa untuk kabupaten/kota, kecamatan, desa/kelurahan
if (isLoading) CircularProgressIndicator(),
],
);
}
}
Contoh-contoh ini menunjukkan bagaimana mengintegrasikan dengan API Laravel Nusa dari berbagai platform dan bahasa pemrograman, menyediakan fondasi yang kuat untuk membangun formulir alamat dan fitur berbasis lokasi di aplikasi Anda.