Absensi GPS
Arsitektur Sistem
Backend
Frontend
API
  • Struktur
  • Alur Kerja
  • Implementasi GPS
  • Pengembangan dan Pengujian
Deployment
Pengujian
Arsitektur Sistem
Backend
Frontend
API
  • Struktur
  • Alur Kerja
  • Implementasi GPS
  • Pengembangan dan Pengujian
Deployment
Pengujian
  • API (Application Programming Interface)

API (Application Programming Interface)

Pendahuluan

API (Application Programming Interface) pada aplikasi Absensi GPS digunakan untuk komunikasi antara aplikasi Android dan backend Laravel. API ini menggunakan format JSON dan mengimplementasikan autentikasi menggunakan API key.

Autentikasi API

Semua endpoint API untuk aplikasi mobile dilindungi dengan autentikasi API key. Setiap request harus menyertakan header Authorization dengan format:

Authorization: Bearer <api_key>

API key disimpan dalam file .env dengan nama MOBILE_API_KEY.

Middleware ValidateApiKey

Autentikasi API key diimplementasikan menggunakan middleware ValidateApiKey:

class ValidateApiKey
{
    public function handle(Request $request, Closure $next): Response
    {
        // Ambil API key dari .env
        $validApiKey = env('MOBILE_API_KEY');
        // Ambil API key dari header Authorization
        $providedApiKey = $request->header('Authorization');

        // Support format: "Bearer <api_key>" atau langsung "<api_key>"
        if ($providedApiKey && str_starts_with($providedApiKey, 'Bearer ')) {
            $providedApiKey = substr($providedApiKey, 7);
        }

        if (!$providedApiKey || $providedApiKey !== $validApiKey) {
            return response()->json([
                'success' => false,
                'message' => 'Unauthorized: Invalid API key',
            ], 401);
        }

        return $next($request);
    }
}

Endpoint API

1. Cek Status Server

Endpoint ini digunakan oleh aplikasi Android untuk memeriksa status server dan mendapatkan informasi IP server.

  • URL: /api/mobile/status
  • Method: GET
  • Autentikasi: API Key
  • Response:
{
  "success": true,
  "data": {
    "status": "online",
    "database": "online",
    "server_ip": "192.168.1.100",
    "server_time": "2025-05-15 20:30:00",
    "app_version": "1.0.0"
  }
}

2. Autentikasi Siswa

Endpoint ini digunakan untuk autentikasi siswa pada aplikasi Android.

  • URL: /api/mobile/auth/login
  • Method: POST
  • Autentikasi: API Key
  • Request Body:
{
  "id_siswa": "S123456",
  "password": "password"
}
  • Response Success:
{
  "success": true,
  "message": "Login berhasil",
  "data": {
    "siswa": {
      "id": 1,
      "id_siswa": "S123456",
      "nama": "Budi Santoso",
      "kelas": {
        "id": 1,
        "nama_kelas": "X IPA 1"
      }
    }
  }
}
  • Response Error:
{
  "success": false,
  "message": "ID Siswa atau password salah"
}

3. Absensi Masuk

Endpoint ini digunakan untuk melakukan absensi masuk.

  • URL: /api/mobile/absensi/masuk
  • Method: POST
  • Autentikasi: API Key
  • Request Body:
{
  "siswa_id": 1,
  "lokasi": "-6.1234,106.8456"
}
  • Response Success:
{
  "success": true,
  "message": "Absensi masuk berhasil",
  "data": {
    "tanggal": "2025-05-15",
    "waktu_masuk": "07:30:00",
    "status": "hadir"
  }
}
  • Response Error (Sudah Absen):
{
  "success": false,
  "message": "Anda sudah melakukan absensi masuk hari ini"
}

4. Absensi Keluar

Endpoint ini digunakan untuk melakukan absensi keluar.

  • URL: /api/mobile/absensi/keluar
  • Method: POST
  • Autentikasi: API Key
  • Request Body:
{
  "siswa_id": 1,
  "lokasi": "-6.1234,106.8456"
}
  • Response Success:
{
  "success": true,
  "message": "Absensi keluar berhasil",
  "data": {
    "tanggal": "2025-05-15",
    "waktu_masuk": "07:30:00",
    "waktu_keluar": "14:30:00",
    "status": "hadir"
  }
}
  • Response Error (Belum Absen Masuk):
{
  "success": false,
  "message": "Anda belum melakukan absensi masuk hari ini"
}
  • Response Error (Sudah Absen Keluar):
{
  "success": false,
  "message": "Anda sudah melakukan absensi keluar hari ini"
}

5. Status Absensi

Endpoint ini digunakan untuk memeriksa status absensi siswa hari ini.

  • URL: /api/mobile/absensi/status
  • Method: GET
  • Autentikasi: API Key
  • Query Parameter: siswa_id=1
  • Response:
{
  "success": true,
  "data": {
    "siswa": {
      "id": 1,
      "id_siswa": "S123456",
      "nama": "Budi Santoso",
      "kelas": {
        "id": 1,
        "nama_kelas": "X IPA 1"
      }
    },
    "absensi": {
      "tanggal": "2025-05-15",
      "sudah_absen_masuk": true,
      "sudah_absen_keluar": false,
      "waktu_masuk": "07:30:00",
      "waktu_keluar": null,
      "status": "hadir"
    }
  }
}

Implementasi Controller

ServerStatusController

class ServerStatusController extends Controller
{
    public function status(Request $request)
    {
        // Cek koneksi database
        $dbStatus = 'online';
        try {
            DB::connection()->getPdo();
        } catch (\Exception $e) {
            $dbStatus = 'offline';
        }

        // Mendapatkan IP server
        $serverIp = $request->server('SERVER_ADDR');
        if (!$serverIp) {
            $serverIp = gethostbyname(gethostname());
        }

        // Mendapatkan waktu server
        $serverTime = now()->format('Y-m-d H:i:s');

        return response()->json([
            'success' => true,
            'data' => [
                'status' => 'online',
                'database' => $dbStatus,
                'server_ip' => $serverIp,
                'server_time' => $serverTime,
                'app_version' => config('app.version', '1.0.0'),
            ],
        ]);
    }
}

AuthController

class AuthController extends Controller
{
    public function login(Request $request)
    {
        $request->validate([
            'id_siswa' => 'required|string',
            'password' => 'required|string',
        ]);

        $siswa = Siswa::where('id_siswa', $request->id_siswa)->first();

        if (!$siswa || !Hash::check($request->password, $siswa->password)) {
            return response()->json([
                'success' => false,
                'message' => 'ID Siswa atau password salah',
            ], 401);
        }

        // Ambil data kelas
        $siswa->load('kelas');

        return response()->json([
            'success' => true,
            'message' => 'Login berhasil',
            'data' => [
                'siswa' => [
                    'id' => $siswa->id,
                    'id_siswa' => $siswa->id_siswa,
                    'nama' => $siswa->nama,
                    'kelas' => [
                        'id' => $siswa->kelas->id,
                        'nama_kelas' => $siswa->kelas->nama_kelas,
                    ],
                ],
            ],
        ]);
    }
}

AbsensiMobileController

class AbsensiMobileController extends Controller
{
    public function absenMasuk(Request $request)
    {
        $request->validate([
            'siswa_id' => 'required|exists:siswa,id',
            'lokasi' => 'required|string',
        ]);

        $siswaId = $request->siswa_id;
        $lokasi = $request->lokasi;
        $tanggal = Carbon::now()->format('Y-m-d');
        
        // Cek apakah sudah absen hari ini
        $absensiHariIni = Absensi::where('siswa_id', $siswaId)
            ->where('tanggal', $tanggal)
            ->first();
        
        if ($absensiHariIni) {
            // Jika sudah absen masuk
            if ($absensiHariIni->waktu_masuk) {
                return response()->json([
                    'success' => false,
                    'message' => 'Anda sudah melakukan absensi masuk hari ini',
                ], 400);
            }
            
            // Update absensi yang sudah ada
            $absensiHariIni->waktu_masuk = Carbon::now()->format('H:i:s');
            $absensiHariIni->lokasi_masuk = $lokasi;
            $absensiHariIni->status = 'hadir';
            $absensiHariIni->save();
            
            return response()->json([
                'success' => true,
                'message' => 'Absensi masuk berhasil',
                'data' => [
                    'tanggal' => $tanggal,
                    'waktu_masuk' => $absensiHariIni->waktu_masuk,
                    'status' => $absensiHariIni->status,
                ],
            ]);
        } else {
            // Buat absensi baru
            $absensi = new Absensi();
            $absensi->siswa_id = $siswaId;
            $absensi->tanggal = $tanggal;
            $absensi->waktu_masuk = Carbon::now()->format('H:i:s');
            $absensi->lokasi_masuk = $lokasi;
            $absensi->status = 'hadir';
            $absensi->save();
            
            return response()->json([
                'success' => true,
                'message' => 'Absensi masuk berhasil',
                'data' => [
                    'tanggal' => $tanggal,
                    'waktu_masuk' => $absensi->waktu_masuk,
                    'status' => $absensi->status,
                ],
            ]);
        }
    }
    
    public function absenKeluar(Request $request)
    {
        $request->validate([
            'siswa_id' => 'required|exists:siswa,id',
            'lokasi' => 'required|string',
        ]);

        $siswaId = $request->siswa_id;
        $lokasi = $request->lokasi;
        $tanggal = Carbon::now()->format('Y-m-d');
        
        // Cek apakah sudah absen masuk hari ini
        $absensiHariIni = Absensi::where('siswa_id', $siswaId)
            ->where('tanggal', $tanggal)
            ->first();
        
        if (!$absensiHariIni || !$absensiHariIni->waktu_masuk) {
            return response()->json([
                'success' => false,
                'message' => 'Anda belum melakukan absensi masuk hari ini',
            ], 400);
        }
        
        // Jika sudah absen keluar
        if ($absensiHariIni->waktu_keluar) {
            return response()->json([
                'success' => false,
                'message' => 'Anda sudah melakukan absensi keluar hari ini',
            ], 400);
        }
        
        // Update absensi dengan waktu keluar
        $absensiHariIni->waktu_keluar = Carbon::now()->format('H:i:s');
        $absensiHariIni->lokasi_keluar = $lokasi;
        $absensiHariIni->save();
        
        return response()->json([
            'success' => true,
            'message' => 'Absensi keluar berhasil',
            'data' => [
                'tanggal' => $tanggal,
                'waktu_masuk' => $absensiHariIni->waktu_masuk,
                'waktu_keluar' => $absensiHariIni->waktu_keluar,
                'status' => $absensiHariIni->status,
            ],
        ]);
    }
    
    public function statusAbsensi(Request $request)
    {
        $request->validate([
            'siswa_id' => 'required|exists:siswa,id',
        ]);

        $siswaId = $request->siswa_id;
        $tanggal = Carbon::now()->format('Y-m-d');
        
        // Ambil data siswa
        $siswa = Siswa::with('kelas')->find($siswaId);
        
        // Cek absensi hari ini
        $absensiHariIni = Absensi::where('siswa_id', $siswaId)
            ->where('tanggal', $tanggal)
            ->first();
        
        $statusAbsen = [
            'tanggal' => $tanggal,
            'sudah_absen_masuk' => false,
            'sudah_absen_keluar' => false,
            'waktu_masuk' => null,
            'waktu_keluar' => null,
            'status' => 'belum_absen',
        ];
        
        if ($absensiHariIni) {
            $statusAbsen['sudah_absen_masuk'] = $absensiHariIni->waktu_masuk !== null;
            $statusAbsen['sudah_absen_keluar'] = $absensiHariIni->waktu_keluar !== null;
            $statusAbsen['waktu_masuk'] = $absensiHariIni->waktu_masuk;
            $statusAbsen['waktu_keluar'] = $absensiHariIni->waktu_keluar;
            $statusAbsen['status'] = $absensiHariIni->status;
        }
        
        return response()->json([
            'success' => true,
            'data' => [
                'siswa' => [
                    'id' => $siswa->id,
                    'id_siswa' => $siswa->id_siswa,
                    'nama' => $siswa->nama,
                    'kelas' => [
                        'id' => $siswa->kelas->id,
                        'nama_kelas' => $siswa->kelas->nama_kelas,
                    ],
                ],
                'absensi' => $statusAbsen,
            ],
        ]);
    }
}

Registrasi Route API

Route API didaftarkan dalam file routes/api.php:

// API Mobile untuk Android
// API untuk cek status server (untuk scanning dari Android)
Route::get('/mobile/status', [ServerStatusController::class, 'status'])->middleware(ValidateApiKey::class);

// API untuk autentikasi siswa
Route::post('/mobile/auth/login', [AuthController::class, 'login'])->middleware(ValidateApiKey::class);

// API untuk absensi
Route::middleware(ValidateApiKey::class)->group(function () {
    // Absensi masuk
    Route::post('/mobile/absensi/masuk', [AbsensiMobileController::class, 'absenMasuk']);
    
    // Absensi keluar
    Route::post('/mobile/absensi/keluar', [AbsensiMobileController::class, 'absenKeluar']);
    
    // Status absensi hari ini
    Route::get('/mobile/absensi/status', [AbsensiMobileController::class, 'statusAbsensi']);
});

Pengujian API

Untuk menguji API, Anda dapat menggunakan tools seperti Postman atau cURL. Berikut adalah contoh pengujian menggunakan cURL:

Cek Status Server

curl -X GET \
  "http://localhost:8000/api/mobile/status" \
  -H "Authorization: Bearer 9a3b7c8d2e1f4a5b6c7d8e9f0a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8"

Login Siswa

curl -X POST \
  "http://localhost:8000/api/mobile/auth/login" \
  -H "Authorization: Bearer 9a3b7c8d2e1f4a5b6c7d8e9f0a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8" \
  -H "Content-Type: application/json" \
  -d '{
    "id_siswa": "S123456",
    "password": "password"
}'

Absen Masuk

curl -X POST \
  "http://localhost:8000/api/mobile/absensi/masuk" \
  -H "Authorization: Bearer 9a3b7c8d2e1f4a5b6c7d8e9f0a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8" \
  -H "Content-Type: application/json" \
  -d '{
    "siswa_id": 1,
    "lokasi": "-6.1234,106.8456"
}'

Kesimpulan

API pada aplikasi Absensi GPS menyediakan endpoint yang diperlukan untuk aplikasi Android dalam melakukan absensi siswa. Dengan menggunakan autentikasi API key, API ini menjamin keamanan data yang dikirimkan antara aplikasi Android dan backend Laravel.

Last Updated:: 5/15/25, 9:30 PM
Contributors: Nur Wahyudin