Tulisan ini bermula dari pertanyaan yang muncul di benak saya. Bagaimana aplikasi bawaan Apple seperti Notes, Reminders, Photos, dapat berjalan di web, meskipun datanya bersifat privat dan tersimpan di dalam akun iCloud pengguna?
Ternyata jawabannya adalah CloudKit. CloudKit adalah sebuah framework database yang dibuat oleh Apple. Namun tidak hanya fokus dibuat untuk menyimpan data, CloudKit juga menganut prinsip "local-first". Ini berarti data akan disimpan secara lokal di perangkat Apple terlebih dahulu, yang kemudian dapat disinkronkan ke CloudKit database. CloudKit menyediakan 2 jenis database:
- CloudKit Private Database: Penyimpanan data yang aman dan privat dalam akun iCloud pengguna. Cocok untuk aplikasi yang menyimpan data-data personal seperti Apple Notes, Reminders, dan Photos.
- CloudKit Public Database: Penyimpanan data publik yang tidak terkait dengan akun iCloud tertentu. Sehingga semua orang dapat mengaksesnya. Cocok untuk aplikasi yang datanya dikonsumsi secara publik seperti Apple App Store, musik yang dapat didengarkan di Apple Music, juga film maupun series di Apple TV (ini hanya sebagai contoh penggunaan, bukan data sebenarnya).
Dalam tulisan ini, saya akan fokus membahas CloudKit Private Database. Saya akan berbagi pengalaman saya dan sedikit gambaran tentang cara mengintegrasikan CloudKit dengan aplikasi web. Meskipun saya menggunakan Next.js, kode JavaScript yang saya tulis disini bersifat umum dan dapat digunakan di framework lainnya.
Daftar Isi
- Prasyarat
- Mulai
- Step 1 — Akses CloudKit Console
- Step 2 — CloudKit API Key
- Step 3 — integrating CloudKit Web Services
- Penutup
Prasyarat
- Anda memiliki Apple Developer Account yang aktif. Biaya keanggotaannya adalah $99 USD per tahun.
- Anda sudah atau sedang mengembangkan aplikasi untuk platform Apple (iOS, macOS, atau yang lainnya) yang telah dikonfigurasi untuk menggunakan CloudKit.
- Anda familiar dengan bahasa pemrograman JavaScript dan Next.js.
Mulai
Apple menyediakan beberapa cara untuk mengakses data CloudKit dengan JavaScript. Beberapa caranya:
- CloudKit Web Services - Ini adalah cara yang akan kita gunakan. Sebuah API service yang disediakan Apple untuk mengakses CloudKit. Menurut saya, cara ini merupakan pilihan terbaik saat ini.
- CloudKit.js - Sebuah library JavaScript yang disediakan Apple. Namun, library ini sudah tidak diperbarui oleh Apple, sehingga beberapa orang menyarankan untuk tidak menggunakannya lagi (lihat salah satu contoh).
- CKTool JS - Sebuah library Node.js yang dirilis Apple pada tahun 2022. Namun, library ini lebih berfokus untuk melakukan otomasi (lihat contoh).
Step 1 — Akses CloudKit Console
Langkah pertama yang harus kita lakukan adalah memastikan kita dapat melihat CloudKit container yang telah dikonfigurasi sebelumnya. Caranya:
- Buka CloudKit Console — icloud.developer.apple.com/dashboard.
- Login menggunakan akun Apple Developer Account Anda.
- Klik "CloudKit Database".
- Jika Anda melihat tampilan seperti ini, berarti Anda sudah berhasil mengakses CloudKit Console.
- Gunakan dropdown di pojok kiri atas untuk memilih project yang ingin Anda akses. Dropdown ini akan menampilkan bundle ID aplikasi Anda yang telah terintegrasi dengan CloudKit.
Mengaktifkan Query
Selanjutnya, kita perlu menambahkan satu index baru ke dalam pengaturan tabel agar kita dapat melakukan query ke tabel tersebut.
-
Pilih menu "Schema" → "Indexes".
-
Pastikan Anda melihat daftar Indexes yang sudah ada sebelumnya. Biasanya item-item ini memiliki format
CD_<column_name>
. -
Jika Anda sudah melihatnya, klik tombol tambah di atas.
-
Lalu isi form seperti gambar dibawah ini.
- Record Type - Pilih tabel yang Anda gunakan.
- Name - Isi dengan nama yang mudah diingat. Biasanya, saya menggunakan nama yang sama dengan
Field
yang ada di bawah. - Type - Pilih
QUERYABLE
agar tabel kita dapat di query dari CloudKit Console. - Field - Pilih
recordName
dari dropdown.
Mencoba Melakukan Query
Setelah mengaktifkan query, kita perlu memastikan bahwa kita dapat melakukan query dari CloudKit Console.
-
Pilih menu "Data" → "Records".
-
Atur opsi untuk melakukan query:
- Database: Pilih "Private Database".
- Record Zone: Pilih "com.apple.coredata.cloudkit.zone". Ini adalah record zone yang dibuat oleh CoreData atau SwiftData pada saat kita mengintegrasikannya ke dalam iOS app.
- Record Type (opsi berwarna biru di bawah opsi Database): Pilih tabel yang ingin Anda query. Dalam project saya, tabelnya bernama
CD_Todo
.
Setelah semua sudah dipilih, klik "Query Records".
Hasil query akan bervariasi tergantung seberapa banyak data yang Anda miliki. Jika Anda belum menambahkan data apapun, tampilannya akan kosong. Jika sudah, kurang lebih akan seperti gambar di atas.
Setelah Anda berhasil melakukan query, Anda juga dapat mengubah data langsung dari dashboard ini jika diperlukan.
Step 2 — CloudKit API Key
Untuk mengakses CloudKit dari aplikasi web, kita perlu membuat API key.
-
Pilih menu "Settings" → "Token & Keys", lalu klik pada icon plus di sebelah tulisan "API Tokens".
-
Isi form pembuatan API key:
-
Name - Beri nama yang mudah diingat, misalnya "Next.js API Key".
-
Sign in Callback
- Pilih "URL Redirect", lalu pada dropdown pilih "localhost".
- Isi port localhost Anda (default Next.js berjalan di port
3000
). - Isi URL path, dalam contoh ini saya menggunakan
/api/auth/callback
.
- Pilih "URL Redirect", lalu pada dropdown pilih "localhost".
Biarkan pilihan lainnya.
-
-
Jika sudah, simpan API key yang sudah dibuat di tempat yang aman.
Sangat penting untuk menjaga kerahasiaan API key ini. Jangan pernah membagikan atau mempublikasikan API key Anda.
Step 3 — Integrating CloudKit Web Services
Sekarang kita akan mulai mengintegrasikan CloudKit ke dalam aplikasi Next.js kita menggunakan CloudKit Web Services API. Kita akan mulai dari autentikasi, membuat API endpoints, dan yang terakhir memanggilnya dari sisi client (frontend).
Environment Variables
Beberapa data penting diperlukan untuk dapat mengintegrasikan CloudKit. Simpan semua data ini di environment variables.
- Apple CloudKit API Key - Data ini merupakan data sensitif dan hanya boleh digunakan di server. Jangan pernah menyertakannya dalam client bundle.
- Container - Nama bundle ID aplikasi Anda.
- Environment - Pilih antara
development
atauproduction
. Seperti namanya ini cukup menjelaskan ya, jika Anda menggunakannya di dalam proses development, maka gunakandevelopment
. Lalu saat Anda sudah siap merilisnya, gunakanproduction
.
Seperti ini contoh file .env
nya:
Untuk dapat melakukan request ke CloudKit, kita memerlukan API URL nya. Format API URL-nya seperti ini:
${container}
: value-nya adalahAPPLE_CK_CONTAINER
.${environment}
: value-nya adalahAPPLE_CK_ENVIRONMENT
./private
: memberi petunjuk kepada CloudKit jika kita hanya ingin mengakses CloudKit Private Database.
Simpan URL ini dalam sebuah file JavaScript terpisah agar mudah digunakan.
Autentikasi
Autentikasi CloudKit Web Services cukup sederhana. Langkah-langkah nya seperti ini:
Backend (Server)
-
Login Request: Pertama, kita akan melakukan request ke API
/users/current
untuk melakukan login. Kita perlu membuat API endpoint di sisi server untuk melakukan request tersebut.Untuk informasi lebih detail tentang API
/users/current
, lihat dokumentasi lengkapnya. -
Auth Callback Handler: Lalu kita juga perlu membuat API endpoint untuk menghandle callback yang diberikan Apple. Sebelum menulis kodenya, kita membutuhkan satu library tambahan yaitu cookies-next untuk memudahkan kita menambahkan, mengubah dan menghapus cookies di server.
Frontend (Client)
Sekarang kita akan mengimplementasikan bagian frontend dan menghubungkannya dengan API endpoints yang sudah kita buat. Kita buat dahulu halaman-halaman frontend nya. Sebagai contoh, saya hanya akan membuat 2 halaman saja: /
sebagai halaman utama, dan /login
.
Selanjutnya, kita akan fokus di halaman login terlebih dahulu. Mari kita hubungkan halaman tersebut dengan API login yang sudah kita buat.
Setelah pengguna berhasil login, Apple akan mengarahkan mereka ke API endpoint callback kita (/api/auth/callback
). Dari sana, pengguna akan diarahkan kembali ke halaman utama.
Saat ini, kita masih dapat langsung mengakses halaman utama walaupun kita belum login. Untuk itu kita dapat menambahkan proteksi ke halaman tersebut dengan Next.js Middleware.
Mengakses Data
Setelah berhasil melakukan autentikasi, kita dapat mulai mengakses data CloudKit. Ada beberapa hal yang penting untuk diperhatikan:
-
Keamanan
- Semua request ke CloudKit Web Services harus dilakukan dari server-side.
- Data
APPLE_CK_API_KEY
yang ada di environment variables tidak boleh digunakan di client-side. Jika Anda menaruhnya di client-side maka Anda membocorkannya ke publik. - Data
ckWebAuthToken
sudah kita simpan di dalam cookies dan dapat diakses di server. Kita tidak perlu mengirimnya dari sisi client.
-
Implementasi
- Dengan Next.js, kita dapat menggunakan API Routes (server) untuk menangani request ke CloudKit Web Services dengan aman.
- Langkah-langkah di bawah ini hanya menunjukan cara dasar melakukan request ke CloudKit Web Services. Anda perlu menambahkan hal-hal lain seperti validasi dan langkah-langkah keamanan lainnya sesuai kebutuhan.
Query Data
Untuk melakukan query data, kita dapat menggunakan API /records/query
. Contoh API endpoint-nya seperti ini:
Beberapa hal penting dalam request payload:
-
zoneID.zoneName
Field ini wajib diisi. Isi dengan
com.apple.coredata.cloudkit.zone
untuk mengambil data dari record zone yang sama seperti yang kita gunakan di aplikasi native kita. -
query
Field ini wajib diisi. Field ini bentuknya adalah object yang dapat diisi sesuai query yang kita inginkan. Dalam contoh di atas, saya mengambil data dari record type (tabel)
CD_Todo
dan diurutkan dariCD_createdAt
yang terbaru (ascending: false
). Untuk detail query request yang lainnya seperti filter (where clause), pelajari di dokumentasi.
Selanjutnya adalah response dari API tersebut. Ada cukup banyak detail-detail yang sebenarnya tidak kita perlukan di tampilan data kita. Sementara data yang kita perlukan hanya 3 data ini:
-
record.recordName
Apple menggunakan
recordName
sebagai unique identifier untuk setiap data. Data ini akan kita gunakan untuk menampilkan dan memanipulasi data tersebut. -
record.recordChangeTag
Apple menggunakan field ini untuk manajemen perubahan data dalam prinsip "local-first". Kita harus menyertakan tag ini saat melakukan perubahan atau penghapusan data, agar Apple dapat melacak perubahannya.
-
record.fields
Data ini berisi data utama yang kita simpan. Misalnya, jika kita menyimpan
title
&isCompleted
seperti contoh di atas, kita dapat mengakses kedua informasi tersebut melaluirecord.fields
.
Untuk melihat response lengkap dari API tersebut, lihat di dokumentasi.
Manipulasi Data
Untuk memanipulasi data di CloudKit, kita menggunakan API /records/modify
. API ini memungkinkan kita untuk melakukan operasi penambahan, perubahan, dan penghapusan data. Juga, jika dibutuhkan, API ini dapat melakukan operasi bulk.
Ini adalah format dasar yang kita request ke API /records/modify
:
Field operations
berbentuk array. Hal ini yang memungkinkan kita untuk melakukan berbagai operasi dalam satu request (bulk). Semua operasi bentuknya akan mirip-mirip seperti format di atas, yang akan membedakan hanya isi dari field operations
.
Tambah Data
Untuk menambahkan data baru, kita dapat menaruhnya di dalam field operations
seperti ini:
operationType
- Tipe operasi yang diinginkan. Untuk menambah data baru, gunakancreate
.record.recordType
- Nama tabel yang digunakan. Dalam contoh ini saya menggunakan tabelCD_Todo
.record.fields
- Data yang ingin kita simpan dan harus sesuai dengan schema yang sudah ada di CloudKit.- Perhatikan field tambahan:
CD_entityName
, yang valuenya sama sepertirecord.recordType
namun tanpa prefixCD_
, jadi hanyaTodo
saja.
- Perhatikan field tambahan:
Pelajari lebih lanjut tentang penambahan data.
Ubah Data
Untuk mengubah data, kita dapat menaruhnya di field operations
seperti ini:
Proses perubahan data mirip dengan penambahan data, namun dengan beberapa perbedaan penting:
operationType: 'update'
- Gunakan tipe operasi 'update' untuk mengubah data yang sudah ada.record.recordName
- Sertakan ID yang ingin diubah.record.recordChangeTag
- Sertakan 'recordChangeTag' dari data yang ingin diubah.record.fields
- Hanya sertakan field-field yang ingin diubah. Tidak perlu menyertakan seluruh data jika hanya sebagian yang diubah.
Pelajari lebih lanjut tentang perubahan data.
Hapus Data
Untuk menghapus data, kita bisa menaruhnya di field operations
seperti ini:
Sama seperti sebelumnya, kode yang berubah hanya yang ada di dalam operations
saja. Informasi yang dikirimkan lebih sederhana:
operationType: 'delete'
- Gunakan tipe operasi 'delete' untuk menghapus data.record.recordName
- Sertakan ID yang akan dihapus.record.recordChangeTag
- Sertakan 'recordChangeTag' dari data yang ingin dihapus.
Pelajari lebih lanjut tentang penghapusan data.
Menggunakan Data di Frontend
Setelah mengimplementasikan semua API untuk operasi CRUD (Create, Read, Update, Delete), kita dapat menggunakannya di frontend. Saya hanya akan menuliskan bentuk-bentuk contoh saja, supaya Anda mendapatkan gambaran bagaimana cara menggunakannya.
Catatan Penting: Contoh-contoh berikut hanya untuk ilustrasi dan tidak disarankan untuk versi production. Saya menyarankan Anda untuk menggunakan library seperti @tanstack/react-query atau swr untuk mempermudah mengelola asynchronous API calls.
Query Data
Untuk menampilkan data, gunakan API /api/todos
yang sudah kita buat sebelumnya. Misalnya seperti ini:
Tambah Data
Untuk menambahkan data, gunakan API /api/todos/create
yang sudah kita buat sebelumnya. Misalnya seperti ini:
Ubah & Hapus Data
-
Untuk mengubah data, gunakan API
/api/todos/update
yang sudah kita buat sebelumnya. Misalnya seperti ini: -
Untuk menghapus data, gunakan API
/api/todos/delete
yang sudah kita buat sebelumnya. Misalnya seperti ini:
Perlu diingat bahwa contoh-contoh ini adalah implementasi dasar. Dalam aplikasi production, Anda perlu menambahkan penanganan error, loading states, dan optimisasi performa. Penggunaan library state-management dan data-fetching dapat sangat membantu dalam mengelola kompleksitas ini.
Penutup
Mengintegrasikan CloudKit Web Services ke dalam aplikasi web ternyata tidak serumit yang saya bayangkan. Kunci keberhasilannya ada pada ketekunan dan kegigihan dalam menelusuri dan memahami dokumentasi yang disediakan oleh Apple.
Tulisan ini merupakan hasil pengembangan dari apa yang saya pelajari dari dokumentasi resmi Apple. Bagi Anda yang serius ingin mengembangkan aplikasi web dengan CloudKit, saya sangat menyarankan untuk meluangkan waktu lebih banyak untuk mempelajari dokumentasinya secara menyeluruh.
Untuk referensi implementasi yang lebih lengkap dan menyeluruh, saya telah menyediakan kodenya di GitHub. Namun, perlu diingat bahwa kode tersebut hanya untuk environment development
saja, dan belum diuji secara menyeluruh untuk environment production
. Jika Anda berniat menggunakannya, lakukan dengan bijak — tambahkan fitur keamanan dan pengujian tambahan. Singkatnya, Do With Your Own Risk (DWYOR).
Jika Anda memiliki pertanyaan atau membutuhkan penjelasan lebih lanjut, jangan ragu untuk menghubungi saya di Twitter. Selamat mencoba!