DEV Community

Cover image for Rest API Menggunakan Dart
Catur Wicaksono
Catur Wicaksono

Posted on

Rest API Menggunakan Dart

Artikel ini adalah tutorial pembuatan REST API dengan menggunakan bahasa Dart. Tutorial ini akan terasa cukup panjang, dengan membahas pembuatan REST API dengan menggunakan Dart. Dari menerima http request dari client berupa test dan menerima file upload dari client ke aplikasi REST API server Dart kita.

Persiapan

Sebelum lebih jauh, kita akan mempersiapkan terlebih dahulu apa saja yang kita perlukan dalam membuat REST API ini. Pada seri kali ini, kita memerlukan beberapa hal berikut ini:

  1. Visual Studio Code (VSCode). Kita akan menggunakan VSCode untuk code editor kita. karena VSCode sudah menyediakan plug-in yang dapat mempermudah pengerjaan kita nantinya.

  2. Dart SDK. Untuk membuat REST API dengan menggunakan DART, sudah tentu kita memerlukan bahasa Dart itu sendiri terinstall pada perangkat kia.

Intalasi VS Code

Bagi yang belum menginstall aplikasi VSCode pada perangkat masing-masing, dapat mengunjungi halaman website VS Code. Berikut ini tampilan untuk halaman website VSCode.

Halaman website VS Code

Pada halaman awal VSCode sudah disediakan link untuk men-download installer, dan VSCode sudah dapat memprediksi operating system yang kita gunakan, sehingga link download installer sudah menyesuaikan operating system yang kita gunakan, di sini saya menggunakan Windows dan pada halaman tersebut sudah disediakan installer VS Code untuk Windows.

Selanjutnya silahkan click link download tersebut, untuk men-download installer-nya. Setelah selesai download, lakukan instalasi seperti biasa.

Instalasi Dart SDK

Setelah melakukan instalasi VSCode, selanjutnya yang kita perlukan adalah Dart SDK, untuk melakukan instalasi Dart SDK, sebenarnya sudah dijelaskan pada halaman website dari Dart, untuk operating system Windows disarankan menggunakan Chocolatey. Bagi yang belum menginstal package manager Chocolatey di perangkat masing-masing, dapat melakukan instalasi sesuai dengan halaman website dari Chocolatey pada panduan instalasinya.

Setelah selesai melakukan instalasi Chocolatey, lakukan instalasi Dart dengan menggunakan perintah berikut ini:

choco install dart-sdk
Enter fullscreen mode Exit fullscreen mode

Untuk update Dart SDK dapat menggunakan perintah berikut ini:

choco upgrade dart-sdk
Enter fullscreen mode Exit fullscreen mode

Apabila tidak ada kesalahan maka sekarang Dart SDK sudah berhasil terinstal pada perangkat kita. untuk memeriksanya, kita dapat mengetikkan perintah berikut ini pada command prompt kita:

dart
Enter fullscreen mode Exit fullscreen mode

Perintah di atas akan memunculkan informasi terkait cara penggunaan Dart pada terminal. Dengan demikian kita sudah mempersiapkan alat yang kita butuhkan untuk membuat REST API dengan menggunakan Dart.

Addons VS Code

Penjelasan sebelumnya kenapa pada tutorial ini menggunakan VSCode adalah, karena VSCode menyediakan Addons yang dapat memudahkan pengerjaan kita dalam menggunakan Dart. Pada tutorial kali ini, kita akan menggunakan salah satu addons Dart pada VSCode.

Addons Dart di VS Code

Tambahkanlah addons tersebut pada aplikasi VSCode masing-masing.


Aplikasi REST API Pertama

Setelah kita selesai melakukan persiapan, kita akan memulai membuat aplikasi REST API pertama kita. Pada VSCode kita, buka command palette dengan menekan ctrl + shift + p, Selanjutnya pada kolom palette ketikan dart, sehingga akan muncul pilihan new project, dan pilih new project.

New Project Dart Dengan VS Code

Setelah memilih new project, akan muncul pilihan lagi dan pilih Server App.

Pilihan Project Baru Dengan Dart

Setelah memilih Server App, akan muncul jendela di mana kita akan menempatkan project kita. Kita bebas untuk menempatkan project kita, pilih saja dimana kita akan menempatkannya. Setelah menentukan direktori untuk project kita, selanjutnya VSCode akan meminta nama project baru kita. Kita bebas menentukan nama project baru kita, pada tutorial kali ini, kita akan menggunakan nama default dari plugin, yaitu dart_application_1. Setelah itu, plugin akan melakukan generate data project baru kita secara otomatis. Setelah selesai, maka aplikasi REST API pertama kita sudah siap untuk digunakan.

Project Pertama Dart REST API

Running Aplikasi REST API Pertama Kita

Setelah kita membuat aplikasi pertama kita, kita akan mencoba untuk running aplikasi kita. Kita akan menjalankan aplikasi kita dengan menggunakan terminal command prompt atau powershell di Windows, untuk sistem operasi lain dapat menggunakan terminal pada sistem operasi masing-masing. Pertama kita perlu mengarahkan direktori terminal kita ke direktori project kita, atau cara paling mudah adalah kita membuka terminal melalui VSCode dengan menekan ctrl + shift + c, atau kita juga dapat menggunakan terminal bawaan dari VSCode, untuk menggunakannya, tekan ctrl + j. Untuk menjalankan aplikasi kita, kita perlu menjalankan file utama pada server Dart kita. Pada project default, file utama ada di bin/server.dart. untuk menjalankanya ketikan perintah berikut ini.

dart bin/server.dart
Enter fullscreen mode Exit fullscreen mode

Apabila tidak ada masalah, maka pada terminal kita akan mencetak tulisan 'Server listening on port 8080' yang menandakan server kita telah berjalan di port 8080. Untuk memastikan kalau aplikasi kita berjalan dengan baik, kita dapat mencobanya pada browser kita dengan mengakses halaman localhost:8080. Apabila tidak ada kesalahan, maka alamat tersebut akan memunculkan kalimat 'Hello, World!'.

Review Kode

Kita telah berhasil menjalankan aplikasi REST API pertama kita, selanjutnya kita perlu memahami struktur kode yang baru saja kita jalankan. Pada bundle aplikasi hasil generate dari dart pada langkah awal pada tutorial ini, kita akan banyak bekerja pada direktori bin di mana kita akan menempatkan semua file sistem pada direktori ini. Apabila diperhatikan, pada direktori bin terdapat file server.dart, ini merupakan file utama pada aplikasi kita.

import 'dart:io';

import 'package:shelf/shelf.dart';
import 'package:shelf/shelf_io.dart';
import 'package:shelf_router/shelf_router.dart';

// Configure routes.
final _router = Router()
  ..get('/', _rootHandler)
  ..get('/echo/<message>', _echoHandler);

Response _rootHandler(Request req) {
  return Response.ok('Hello, World!\n');
}

Response _echoHandler(Request request) {
  final message = request.params['message'];
  return Response.ok('$message\n');
}

void main(List<String> args) async {
  // Use any available host or container IP (usually `0.0.0.0`).
  final ip = InternetAddress.anyIPv4;

  // Configure a pipeline that logs requests.
  final handler = Pipeline().addMiddleware(logRequests()).addHandler(_router);

  // For running in containers, we respect the PORT environment variable.
  final port = int.parse(Platform.environment['PORT'] ?? '8080');
  final server = await serve(handler, ip, port);
  print('Server listening on port ${server.port}');
}
Enter fullscreen mode Exit fullscreen mode

Baris kode di atas adalah file server.dart hasil generate dari dart. Pada generated awal, kita akan diberikan dua route sampel untuk bisa kita coba, perhatikan baris kode ini:

final _router = Router()
  ..get('/', _rootHandler)
  ..get('/echo/<message>', _echoHandler);
Enter fullscreen mode Exit fullscreen mode

Baris kode di atas menunjukkan bahwa dart membuatkan kita route sampel yaitu '/' dan '/echo/<message>'. Untuk mencobanya, kita gunakan aplikasi Postman, pastikan terlebih dahulu dart server kita berjalan dengan mengetikkan perintah di terminal dart bin/server.dart.

Menjalankan Route '/'

Untuk mencoba route '/', kita dapat mengetikkan url localhost:8080 dengan method request GET.

Akses Route

Maka kita akan mendapatkan hasil kembalian berupa string 'Hallo World'. Hasil kembalian ini kita dapatkan dari fungsi _rootHandler yang di gunakan pada route '/'. sehingga route untuk '/' sebenarnya menjalankan fungsi _rootHandler.

Menjalankan Route '/echo/<message>'

Untuk mencoba route '/echo/', kita dapat mengetikkan url localhost:8080 dengan method request GET.

Akses Route

Maka kita akan mendapatkan hasil kembalian string 'hallo'. Hasil kembalian ini kita dapatkan dari fungsi _echoHandler yang digunakan pada route '/echo/'. sehingga route untuk '/echo/' sebenarnya menjalankan fungsi _echoHandler.

Seperti contoh di atas, pada penulisan route akan seperti ini '/echo/' namun saat pemanggilan, parameter '' kita ganti dengan string 'hallo'. Dalam REST API dengan menggunakan Dart, untuk melewatkan parameter dapat menggunakan notasi <nama> yang disebut dengan notasi diamond.

Kesimpulan

Konsep dasarnya adalah kita membuat sebuah fungsi dengan parameter object Request, untuk handle sebuah route. untuk menambahkan route lagi, kita hanya perlu membuat fungsi lagi untuk menanganinya, kemudian kita daftarkan pada _router. Kita akan mencobanya setelah ini.


Method Request

Sebelumnya kita telah mencoba membuat REST API kita dengan menggunakan metode GET, selanjutnya kita kan akan mencoba membuat metode request POST dan bagaimana menangkap parameternya, kali ini kita akan mencoba membuat route /greeting. Pertama kita perlu membuat sebuah fungsi untuk menangani route /greeting ini.
kita akan membuat sebuah fungsi seperti berikut ini:

Future<Response> _getPostJsonHandler(Request request) async {
  final content = await request.readAsString();
  var queryParams = Uri(query: content).queryParameters;
  return Response.ok(
    json.encode(queryParams),
    headers: {'Content-type': 'application/json'},
  );
}
Enter fullscreen mode Exit fullscreen mode

Fungsi di atas adalah fungsi untuk menampilkan POST body. Selanjutnya, kita perlu membuat route baru pada _router dan mendaftarkan fungsi _getPostJsonHandler. pada fungsi _router kita rubah menjadi seperti berikut ini:

// Configure routes.
final _router = Router()
  ..get('/', _rootHandler)
  ..get('/echo/<message>', _echoHandler)
  ..post('/getpostdata', _getPostJsonHandler);
Enter fullscreen mode Exit fullscreen mode

Setelah menambahkan route, maka kita dapat mencoba testing route baru kita. Untuk mencobanya, kita perlu mematikan server kita terlebih dahulu dan memulainya kembali. Berikut apabila kita coba menggunakan aplikasi Postman.

Contoh Response Dengan Metode POST

Pada gambar di atas memperlihatkan bahwa hasil response berupa JSON. Langkah selanjutnya, kita dapat mengkreasikan dengan menimpan data tersebut ke database atau menyesuaikan kebutuhan kita nantinya.


Media Upload

Setelah kita berhasil membuat plikasi REST API dengan menerima parameter berupa string baik dengan GET, POST, atau dengan metode request yang lain, selanjutnya kita akan mencoba untuk menerima parameter berupa file. Untuk melakukan ini, kita memerlukan dependensi dari Dart yaitu mime.

Bagi yang masih bingung untuk instalasinya, cukup ketikkan perintah di bawah ini pada terminal yang mengarah pada project kita.

dart pub add mime
Enter fullscreen mode Exit fullscreen mode

Fungsi Controller

Setelah selesai install dependensi mime, maka kita sudah memiliki semua yang dibutuhkan untuk menerima file. Seperti biasa, hal pertama yang perlu kita lakukan adalah dengan membuat fungsi untuk menangani route nantinya. Pada tutorial ini kita akan membuat fungsi untuk menangani upload seperti berikut ini:

Future<Response> _upload(Request request) async {
  final contentType = request.headers['content-type'];
  if (contentType == null) {
    return Response(400, body: 'content-type tidak ditemukan');
  }

  final mediaType = MediaType.parse(contentType);
  if (mediaType.mimeType != 'multipart/form-data') {
    return Response(400, body: 'content-type tidak valid');
  }

  final boundary = mediaType.parameters['boundary'];
  if (boundary == null) {
    return Response(400, body: 'boundary tidak ditemukan');
  }

  final payload = request.read();
  final parts = MimeMultipartTransformer(boundary).bind(payload).where((part) {
    return part.headers['content-type'] == 'image/png';
  });

  final partsIterator = StreamIterator(parts);

  while (await partsIterator.moveNext()) {
    final part = partsIterator.current;

    final file = File('./uploads/testing.png'); // direktori file upload
    if (await file.exists()) {
      await file.delete();
    }
    final chunksIterator = StreamIterator(part);
    while (await chunksIterator.moveNext()) {
      final chunk = chunksIterator.current;
      await file.writeAsBytes(chunk, mode: FileMode.append);
    }

    return Response.ok('Upload Berhasil');
  }

  return Response.ok(payload);
}
Enter fullscreen mode Exit fullscreen mode

Setelah membuat fungsi untuk menangani file upload seperti di atas, selanjutnya kita buat route untuk mengakses fungsi tersebut, pada variabel _router kita ubah menjadi seperti berikut ini:

final _router = Router()
  ..get('/', _rootHandler)
  ..get('/echo/<message>', _echoHandler)
  ..post('/getpostdata', _getPostJsonHandler)
  ..post('/upload', _upload);
Enter fullscreen mode Exit fullscreen mode

Kita menambahkan router /upload pada variabel _router dengan mengakses fungsi _upload.

Setelah kita mempersiapkan fungsi dan juga route-nya, selanjutnya kita persiapkan direktori untuk menampung file yang akan kita upload, pada tutorial ini kita akan menempatkan semua file upload pada filter uploads pada direktori root. Kita akan membuat folder Uploads pada direktori root kita.

Setelah semua siap, selanjutnya kita dapat mulai mencoba untuk menjalankan sistem upload kita. Seperti biasa kita perlu me-restart server kita, kita matikan server kita, dan kita jalankan lagi. Setelah berhasil me-restart, kita jalankan route upload yang baru saja kita buat. Kali ini, kita akan mencoba menjalankannya dengan menggunakan aplikasi Postman.

Contoh Request Upload Gambar

Gambar di atas adalah apabila kita mencoba akses route upload kita dengan menggunakan Postman. Untuk membuktikan apakah file sudah benar-benar berpindah, kita dapat memeriksa folder uploads pada direktori root kita. Sampai di sini, file tutorial dapat diambil pada repositori di bawah ini.


Desain Module

Sesi terakhir pada tutorial kita kali ini adalah untuk membuat aplikasi kita setidaknya mudah untuk di-maintenance. Module aplikasi REST API yang terakhir kita buat, kita akan mencoba memisahkan antara startup file dengan module-module yang lain.

Pertama kita akan memisahkan fungsi _uplaod dan _getPostJsonHandler ke dalam file baru pada folder yang sama, yaitu folder dengan nama file baru user.dart. Selanjutnya, pada file server.dart kita juga akan menghapus fungsi _rootHandler dan _echoHandler beserta route dari fungsi-fungsi tersebut.

Pada file modul user.dart, fungsi _uplaod dan _getPostJsonHandler akan kita sesuaikan supaya dapat di terima pada startup file (server.dart) kita perlu membuat fungsi yang mengembalikan objek router.

class UserApi {
  Router get router {
    final router = Router();



    return router;
  }
}
Enter fullscreen mode Exit fullscreen mode

Pada file user.dart kita akan buat dulu class UserApi, nama kelas ini bebas, dapat disesuaikan sesuai keinginan. pada class UserApi kita membuat sebuah getter yang mengembalikan object Router. Selanjutnya kita akan memindahkan fungsi _uplaod dan _getPostJsonHandler sebelumnya pada blok getter ini. Perhatikan block code berikut ini.

class UserApi {
  Router get router {
    final router = Router();

    router.post('/', (Request request) async {
      return Response.ok(
        headers: {'Content-type': 'application/json'},
        json.encode({
          'code': 200,
          'data': {'name': 'Catur Wicaksono', 'address': 'Jakarta'},
        }),
      );
    });

    router.post('/login', (Request request) async {
      final content = await request.readAsString();
      var queryParams = Uri(query: content).queryParameters;
      return Response.ok(
        headers: {'Content-type': 'application/json'},
        json.encode({
          'code': 200,
          'data': queryParams,
        }),
      );
    });

    router.post('/upload/picture', (Request request) async {
      final contentType = request.headers['content-type'];
      if (contentType == null) {
        return Response(400, body: 'content-type tidak ditemukan');
      }

      final mediaType = MediaType.parse(contentType);
      if (mediaType.mimeType != 'multipart/form-data') {
        return Response(400, body: 'content-type tidak valid');
      }

      final boundary = mediaType.parameters['boundary'];
      if (boundary == null) {
        return Response(400, body: 'boundary tidak ditemukan');
      }

      final payload = request.read();
      final parts =
          MimeMultipartTransformer(boundary).bind(payload).where((part) {
        return part.headers['content-type'] == 'image/png';
      });

      final partsIterator = StreamIterator(parts);

      while (await partsIterator.moveNext()) {
        final part = partsIterator.current;

        final file = File('./uploads/testing.png'); // direktori file upload
        if (await file.exists()) {
          await file.delete();
        }
        final chunksIterator = StreamIterator(part);
        while (await chunksIterator.moveNext()) {
          final chunk = chunksIterator.current;
          await file.writeAsBytes(chunk, mode: FileMode.append);
        }

        return Response.ok('Upload Berhasil');
      }

      return Response.ok(payload);
    });

    return router;
  }
}

Enter fullscreen mode Exit fullscreen mode

Pada baris kode di atas, kita mengimplementasikan fungsi _uplaod dan _getPostJsonHandler sebelumnya, namun dengan cara yang agak berbeda. Perhatikan, nama kedua fungsi menjadi anonymous function yang langsung ditambahkan setelah inisialisasi router. fungsi _uplaod kita tempatkan pada route /upload/picture, dan _getPostJsonHandler pada route /login. Untuk referensi kita akan menambahkan satu route lagi dengam metode get, dengan baris kode seperti di bawah ini.

router.post('/', (Request request) async {
  return Response.ok(
    headers: {'Content-type': 'application/json'},
    json.encode({
      'code': 200,
      'data': {'name': 'Catur Wicaksono', 'address': 'Jakarta'},
    }),
  );
});
Enter fullscreen mode Exit fullscreen mode

Setelah selesai membuat module user, selanjutnya kita gabungkan module user ke startup file kita, server.dart. Pada file server.dart, kita tambahkan module pada variable router sebelumnya seperti berikut ini.

final _router = Router()..mount('/user', UserApi().router);
Enter fullscreen mode Exit fullscreen mode

Untuk menambahkan module, kita gunakan fungsi mount seperti di atas, parameter pertama adalah user, dan parameter kedua adalah object module yang akan ditambahkan.

Dengan demikian cara mengakses route agak sedikit berbeda dari sebelumnya, misal pada module user terdapat route /login, karena module ini ada pada poute /user pada startup file, maka cara mengaksesnya dengan menggunakan router pada startup file terlebih dahulu dan dilanjutkan dengan route module, menjadi /user/login. Kita akan mencobanya dengan menggunakan Postman.

Akses Route Baru Dengan Postman


Untuk source code lengkap untuk tutorial ini, dapat diakses pada repository di bawah ini.


Epilog

Kita cukupkan materi tutorial ini sampai di sini. Sistem yang kita bangun pada tutorial ini masih sangat dasar, sehingga masih perlu banyak pengembangan lagi. Terima kasih telah mengikuti tutorial yang cukup panjang ini.

Latest comments (0)