Flutter & Strapi #1: Provider ile oturum açma kontrolü

Mertcan Kıyak
HardwareAndro
Published in
6 min readMay 9, 2022

Flutter ve Strapi’nin nimetlerinden yararlanarak bir mobil uygulamanın ihtiyaç duyabileceği pek çok detayı elimden geldiğince bu yazı dizisinde anlatmaya çalışacağım.

Bu yazının genel içeriği şu şekilde olacak;

  • Strapi kurulumu
  • Strapi ile örnek bir proje oluşturma
  • Flutter ile örnek bir proje oluşturup, Strapi ile haberleştirme
  • Tabi mobil uygulama içerisinde tüm state (durum) yönetimlerini Provider paketiyle sağlayacağız.

O zaman ilk olarak Strapi nedir bir kaç cümleyle ondan bahsedelim.

Strapi bir Headless CMS’dir. Peki bundan kasıt nedir? Headless CMS’ler bir uygulamanın (mobil veya web) kaynağını oluşturan, endpointler ile istek göndererek haberleşilen yapılardır.

Strapi, tablolar arasında ilişki kurmamızı, medya depolama ve oturum yönetim işlemlerini yapmamızı sağlayan bir Headless CMS hizmetidir.

Strapi Kurulumu

Kurulum işlemi oldukça basit. İlk aşamada bilgisayarımıza NodeJS ve NPM kurulumlarını gerçekleştiriyoruz. Daha sonra Strapi ile proje oluşturup, işlemlerimize başlıyoruz.

Kurulumlarda sorun yaşarsanız bu sayfaya göz atmak yardımcı olacaktır.

NPM;npx create-strapi-app@latest my-project --quickstartyarn;yarn create strapi-app my-project --quickstart

Bir klasör içerisine girip, yukarıdaki komutlardan bir tanesini kullanarak Strapi projemizi oluşturabiliriz. Strapi ile ilk defa proje oluşturuyorsanız biraz vakit alacaktır bu işlem.

Daha önce bir proje oluşturduysanız, proje klasörünün içerisinde cmd yi çalıştırıp

npm run develop

komutunu çalıştırmanız yeterli olacaktır. Strapi’ye giriş yapmak için aşağıdaki bağlantıyı kullanabilirsiniz. Kurulumda bir değişiklik yapmadıysanız localhost’da 1337 portunda Strapi çalışmaya başlayacaktır.

http://localhost:1337/admin/

Proje oluştuktan sonra yönetici hesabı oluşturmanız için tarayıcınızda projenin açılmış olması gerekiyor. Bilgilerinizi yazıp ilerlediğinizde Strapi kullanıma hazır demektir.

Strapi’ye giriş yaptığınızda sizi buna benzer bir ekran karşılayacaktır. (Güncelleme geldikçe değişiyor giriş ekranı)

Strapi anasayfası

Bu içerikte sadece kullanıcının mobil uygulamaya giriş yapmasını sağlayacağımızdan dolayı ilk etapta User koleksiyonunu ile ilgileneceğiz. Bir sonraki aşamada kayıt olma, içerik görüntüleme, içerik yükleme gibi kapsamlı makaleler gelecek.

Sol üstten Content-Manager seçeneğine tıkladığımızda açılan sayfada oluşturduğumuz koleksiyonları görüntülüyoruz. Bu koleksiyonları ilişkisel veritabanlarından da bildiğimiz üzere tablolar olarak düşünebiliriz.

Strapi Collection Sayfası

Sağ üstteki Create new entry ile manuel olarak bir kullanıcı ekleyelim ki bu bilgilerle mobil uygulamamızda giriş yapabilelim.

Confirmed seçeneğini true yapıp, demo bir kullanıcı oluşturup ekledikten sonra Flutter tarafına geçiş yapabiliriz.

Strapi çok daha detaylı bir içeriğin konusu olduğu için Collection-Type, Webhook, Graph gibi kısımları ayrı bir yazıda ele alacağım.

Flutter projemiz oluşa dururken ne yapmak istediğimden özetle bahsedeyim.

Provider paketini kullanarak, kullanıcıdan aldığımız email ve şifre bilgisini, Strapi ile oluşturduğumuz back-end’e post edip, gelen cevaba göre ekranlarımızı oluşturmak.

Uygulamamızın klasör yapısını Veli Bacık hocamızın yayınladığı Flutter Uygulama Mimarisi serisinden detaylıca inceleyebilirsiniz.

Bu içeriğimiz için 3 farklı Flutter paketine ihtiyaç duyuyoruz. Sürümleri farklılık gösterebilir en güncel sürüme pub.dev adresinden ulaşabilirsiniz.

vexana: ^2.8.0
provider: ^6.0.2
get_it: ^7.2.0

Vexana ile servisimize istek gönderip, bu istekleri işliyoruz.

Provider ile ekranlarımızı, istediğimiz durumlara göre yönetiyoruz.

Get_it ile uygulamızda genel bir Singleton yapısı inşa ediyoruz.

Projenin kaynak kodlarına yazının sonundan ulaşabilirsiniz. Ben tüm ayrıntıları ile hangi sayfada ne yapmak istedim anlatmaya başlıyorum.

main.dart’da birden fazla durumu kontrol edip, bu durumlar için oluşturduğumuz ekranları Provider aracılığı ile yansıtıyoruz.

Consumer: Bu widget ile, viewmodel’dan her an gelmesi muhtemel verilerin kullanılacağı kapması belirtiyoruz. Bir nevi, ViewModel’da değişiklik olduğunda Consumer widgeti dışında kalan alanları bu sayfa için görmezden gel ve sadece bu kısmı güncelle. Peki bunu gözlemleyebilir miyiz? Evet.

setState() kullandığımızda her defasında build metodu baştan sona tetikleniyordu hatırlarsanız. Bu yüzden tüm ekran baştan çiziliyordu. Ama Consumer’ı kullandığımız için, sadece değişikliği dinlediğimiz kısımlarda bu yenilemeyi yapıyoruz. Böylelikle ekranı defalarca tekrar tekrar çizmiyoruz.

main.dart dosyasında 41. ve 45.satırın hemen altına bir print atıp console’u gözlemlerseniz ilk açılışta build ve consumer içi, daha sonra uygulama kapatılmadığı sürece sadece consumer içinin çalıştığını göreceksiniz.

Soldaki fotoğrafta uygulama ilk kez açılıyor, sağdakinde ise kullanıcı uygulamaya giriş işlemini gerçekleştiriyor.

Şimdi gelelim servis dosyamızı oluşturup, kullanıcıdan aldığımız bilgileri Strapi’ye gönderelim. Vexana kullanımı oldukça basit ve bir o kadar da işlevsel bir paket o yüzden paket sayfasında ki örnekler anlamamız için fazlasıyla yeterli olacaktır.

LoginService’de Strapi ile oluşturduğumuz back-end’e istek gönderiyoruz. Bu istek sayesinde kullanıcının form ekranında girdiği bilgilerin doğruluğunu kontrol edip, duruma göre giriş yapmasını veya dışarda kalmasını sağlıyoruz.

Servisten dönen ResponseModel’i ise ViewModel’da işliyoruz.

loginViewModel dosyamızda ise kritik noktalardan birisi en üstte tanımladığımız enum’dır. Burada, servisten gelen cevaba göre anlamlı bir ifade olması amacıyla enum yapısını kullanıyoruz. Kullanıcı başarılı giriş yaptıysa 0, hatalı giriş yaptıysa 1, loading ekranında ise 2, ilk defa açılış yaptıysa 3 gibi sayılarla da kontrol edebilirdi ama bu hem kodun okunabilirliğini düşürürdü hem de gelecek yeni durumlara karşı kafa karışıklığına neden olabilirdi.

ViewModel sınıfımızı oluştururken ChangeNotifier sınıfını da ana sınıfımıza ilave etmeliyiz. Bu sayede Provider tarafından fark edilecek ve sınıf içerisindeki değişiklikleri gözlemleyebileceğiz.

LoginViewModel’da kritik kısım notifyListeners(); fonksiyonudur. Bu fonksiyonun kullanılma amacı şudur; Eğer benim değişkenimde bir hareketlenme olursa, bir veri atama işlemi gerçekleşirse hemen bunu kullılan tüm view’lara haber ver ve değişikliği ekrana yansıt.

Eğer notifyListeners()’ı kullanmazsak o değişkeni kullandığımız hiçbir sayfa bu güncellemelerden haberdar olmayacaktır.

Şimdi kullanıcının giriş yapabileceği LoginView’a göz atalım.

Burada tam olarak yaptığımız şey, oluşturduğumuz LoginViewModel ile LoginView’ı haberleştirmek.

Kullanıcıdan alınan bilgiler RequestModel olarak viewmodel’a, viewmodel’dan ise service’e gönderiliyor. Daha sonra servisten gelen cevap bekleniyor, ve durum değişkenleri tetikleniyor. Bu durum değişkenlerini switch case ile karşılaştırıp, hangi durumdaysak o sayfaya yönlendiriyoruz.

Genel bir özet ile yaptığımız işlemleri daha sade bir halde anlatmaya çalışayım.

  • Provider, Vexana ve GetIt paketlerinin kurulumunu sağladık.
  • ResponseModel ve RequestModel isminde iki tane model oluşturduk. Kullanıcıdan form aracılığı ile aldığımız bilgiler RequestModel’da tutuluyor çünkü bu modeli istek olarak servisimize göndereceğiz. ResponseModel’de ise servisten bize dönecek cevap tutuluyor.
  • Servisimizi oluşturduk. Bu servis dosyamızda Strapi’nin bize localhost ip adresini girdik. Bu adres herkeste farklılık göstereceği için burada yazmama gerek yok. cmd’den ipconfig yazıp localhost ip adresiniz ile BASE_URL’e erişebilirsiniz.
  • Get_it paketini kullanarak servisimizi lazy hale getirdik. Bu ne demek? Bu servis dosyasını sadece çağrıldığı anda ve yalnızca 1 defa oluştur demek. lib/product/locator.dart yolunu izleyerek gözlemleyebilirsiniz.
  • ViewModel sınıfımızı oluşturduk ve burada enum tanımladık. Bu enum’lar sayesinde durumlarımızı kolay bir şekilde yönettik. Oluşturduğumuz bu enum’ı sürekli takip edeceğimizden dolayı ViewModel dosyasında notifyListener(); fonksiyonu ile tamamladık.
  • Servis dosyamızda oluşturduğumuz login metodunu ViewModel’da da tanımladık ve servisden gelen veriyi yine Provider aracılığı ile gözlemlenebilir yaptık. ResponseUserModel isimli değişkenimiz içerisinde servisten gelen cevap yer aldığı için ve sürekli değişebileceğinden dolayı yine notifyListener ile tamamladık.
  • View’da ise enumları dinlemeye başladık. Eğer viewmodel dosyamızdaki enum’lar da herhangi bir değişiklik varsa ve bu değişikler switch case şartlarımıza uyuyorsa bizi bu ekranlara yönlendir dedik. Bu sayede viewmodel’da gerçekleşen işlemleri tek bir enum ile kontrol etmiş olduk.
  • main.dart dosyamızda runApp’in üzerine setuplocator fonksiyonumuzu çağırmayı ve MaterialApp widget’ımızı MultiProvider ile sarmalamayı unutmuyoruz.

Yazımızın sonuna geldik. Strapi’yi back-end olarak kullanarak Flutter & Provider altyapısıyla uygulamamızın oturum açma işlemlerini yönettik. Bundan sonraki yazılarda sırasıyla, Kayıt olma, Giriş yapmış kullanıcının bilgilerini cachleme, Strapi de oluşturulan collectionlar ile ilişki kurup verileri uygulamada gösterme konularını ele alacağım.

Buraya kadar okuduğunuz için teşekkür ederim :)

--

--