Flutter - REST API'ye Erişim

Flutter, HTTP kaynaklarını tüketmek için http paketi sağlar. http, Geleceğe dayalı bir kitaplıktır ve await ve async özelliklerini kullanır. Birçok üst düzey yöntem sağlar ve REST tabanlı mobil uygulamaların geliştirilmesini basitleştirir.

Temel konseptler

http paketi, web isteklerini yapmak için yüksek düzeyde bir sınıf ve http sağlar.

  • http sınıfı, tüm HTTP istek türlerini gerçekleştirmek için işlevsellik sağlar.

  • http yöntemleri bir url'yi ve Dart Haritası aracılığıyla ek bilgileri (posta verileri, ek başlıklar vb.) kabul eder. Sunucuyu ister ve yanıtı eşzamansız / bekleme düzeninde geri toplar. Örneğin, aşağıdaki kod, verileri belirtilen url'den okur ve konsolda yazdırır.

print(await http.read('https://flutter.dev/'));

Temel yöntemlerden bazıları aşağıdaki gibidir -

  • read - Belirtilen url'yi GET yöntemi ile isteyin ve yanıtı Future <String> olarak geri döndürün

  • get- Belirtilen url'yi GET yöntemi ile isteyin ve yanıtı Gelecek <Yanıt> olarak geri döndürün. Yanıt, yanıt bilgilerini tutan bir sınıftır.

  • post - Verilen verileri göndererek POST yöntemi aracılığıyla belirtilen url'yi isteyin ve yanıtı Gelecek <Yanıt> olarak geri gönderin

  • put - Belirtilen url'yi PUT yöntemi ile isteyin ve yanıtı Future <Response> olarak geri döndürün

  • head - Belirtilen url'yi HEAD yöntemi ile isteyin ve yanıtı Gelecek <Yanıt> olarak geri döndürün

  • delete - Belirtilen url'yi DELETE yöntemi ile isteyin ve yanıtı Gelecek <Yanıt> olarak geri döndürün

http ayrıca daha standart bir HTTP istemci sınıfı olan istemci sağlar. istemci kalıcı bağlantıyı destekler. Belirli bir sunucuya çok fazla istek yapılması gerektiğinde faydalı olacaktır. Kapatma yöntemi kullanılarak düzgün kapatılması gerekir. Aksi takdirde, http sınıfına benzer. Örnek kod aşağıdaki gibidir -

var client = new http.Client(); 
try { 
   print(await client.get('https://flutter.dev/')); 
} 
finally { 
   client.close(); 
}

Ürün hizmeti API'sine erişim

Bir web sunucusundan ürün verilerini almak için basit bir uygulama oluşturalım ve ardından ürünleri ListView kullanarak gösterelim .

  • Android stüdyosunda yeni bir Flutter uygulaması oluşturun , product_rest_app .

  • Varsayılan başlangıç ​​kodunu (main.dart) product_nav_app kodumuzla değiştirin .

  • Dan klasör varlıkları Kopya product_nav_app için product_rest_app ve pubspec.yaml dosya içindeki varlıkları ekleyin.

flutter: 
   assets: 
      - assets/appimages/floppy.png 
      - assets/appimages/iphone.png 
      - assets/appimages/laptop.png 
      - assets/appimages/pendrive.png 
      - assets/appimages/pixel.png 
      - assets/appimages/tablet.png
  • Http paketini pubspec.yaml dosyasında aşağıda gösterildiği gibi yapılandırın -

dependencies: 
   http: ^0.12.0+2
  • Burada http paketinin en son sürümünü kullanacağız. Android studio, pubspec.yaml dosyasının güncellendiğine dair bir paket uyarısı gönderir.

  • Bağımlılıkları al seçeneğini tıklayın. Android stüdyosu paketi İnternet'ten alacak ve uygulama için uygun şekilde yapılandıracaktır.

  • Http paketini main.dart dosyasında içe aktarın -

import 'dart:async'; 
import 'dart:convert'; 
import 'package:http/http.dart' as http;
  • Aşağıda gösterildiği gibi ürün bilgileriyle yeni bir JSON dosyası, products.json oluşturun -

[ 
   { 
      "name": "iPhone", 
      "description": "iPhone is the stylist phone ever", 
      "price": 1000, 
      "image": "iphone.png" 
   }, 
   { 
      "name": "Pixel", 
      "description": "Pixel is the most feature phone ever", 
      "price": 800, 
      "image": "pixel.png"
   }, 
   { 
      "name": "Laptop", 
      "description": "Laptop is most productive development tool", 
      "price": 2000, 
      "image": "laptop.png" 
   }, 
   { 
      "name": "Tablet", 
      "description": "Tablet is the most useful device ever for meeting", 
      "price": 1500, 
      "image": "tablet.png" 
   }, 
   { 
      "name": "Pendrive", 
      "description": "Pendrive is useful storage medium", 
      "price": 100, 
      "image": "pendrive.png" 
   }, 
   { 
      "name": "Floppy Drive", 
      "description": "Floppy drive is useful rescue storage medium", 
      "price": 20, 
      "image": "floppy.png" 
   } 
]
  • JSONWebServer adlı yeni bir klasör oluşturun ve JSON dosyası, products.json'u yerleştirin.

  • JSONWebServer'ın kök dizini olduğu herhangi bir web sunucusunu çalıştırın ve web yolunu alın. Örneğin, http://192.168.184.1:8000/products.json. Apache, nginx vb. Herhangi bir web sunucusunu kullanabiliriz,

  • En kolay yol, düğüm tabanlı http-sunucu uygulaması kurmaktır. Http-sunucu uygulamasını kurmak ve çalıştırmak için aşağıda verilen adımları izleyin.

    • Nodejs uygulamasını ( nodejs.org ) yükleyin

    • JSONWebServer klasörüne gidin.

cd /path/to/JSONWebServer
  • Npm kullanarak http-server paketini kurun.

npm install -g http-server
  • Şimdi sunucuyu çalıştırın.

http-server . -p 8000 

Starting up http-server, serving . 
Available on: 
   http://192.168.99.1:8000
   http://127.0.0.1:8000 
   Hit CTRL-C to stop the server
  • Lib klasöründe Product.dart adlı yeni bir dosya oluşturun ve Product sınıfını bunun içine taşıyın.

  • Eşlenen veri Haritasını Product nesnesine dönüştürmek için Product.fromMap ürün sınıfına bir fabrika kurucusu yazın. Normalde, JSON dosyası Dart Map nesnesine dönüştürülür ve ardından ilgili nesneye (Ürün) dönüştürülür.

factory Product.fromJson(Map<String, dynamic> data) {
   return Product(
      data['name'],
      data['description'], 
      data['price'],
      data['image'],
   );
}
  • Product.dart'ın tam kodu aşağıdaki gibidir -

class Product {
   final String name; 
   final String description;
   final int price;
   final String image; 
   
   Product(this.name, this.description, this.price, this.image); 
   factory Product.fromMap(Map<String, dynamic> json) { 
      return Product( 
         json['name'], 
         json['description'], 
         json['price'], 
         json['image'], 
      );
   }
}
  • Web sunucusundan ürün bilgilerini almak ve List <Product> nesnesine yüklemek için ana sınıfa iki yöntem yazın - parseProducts ve fetchProducts -.

List<Product> parseProducts(String responseBody) { 
   final parsed = json.decode(responseBody).cast<Map<String, dynamic>>(); 
   return parsed.map<Product>((json) =>Product.fromJson(json)).toList(); 
} 
Future<List<Product>> fetchProducts() async { 
   final response = await http.get('http://192.168.1.2:8000/products.json'); 
   if (response.statusCode == 200) { 
      return parseProducts(response.body); 
   } else { 
      throw Exception('Unable to fetch products from the REST API');
   } 
}
  • Burada aşağıdaki noktalara dikkat edin -

    • Gelecek, ürün bilgilerini tembel olarak yüklemek için kullanılır. Tembel yükleme, kodun çalıştırılmasını gerekli olana kadar erteleyen bir kavramdır.

    • http.get, verileri İnternet'ten almak için kullanılır.

    • json.decode, JSON verilerinin kodunu Dart Map nesnesine çözmek için kullanılır. JSON verilerinin kodu çözüldükten sonra, Product sınıfının fromMap'i kullanılarak List <Product> 'a dönüştürülecektir.

    • MyApp sınıfında, yeni üye değişkeni, Future <Product> türü ürünler ekleyin ve yapıcıya dahil edin.

class MyApp extends StatelessWidget { 
   final Future<List<Product>> products; 
   MyApp({Key key, this.products}) : super(key: key); 
   ...
  • MyHomePage sınıfında, Future <Product> türünde yeni üye değişken ürünleri ekleyin ve bunu yapıcıya dahil edin. Ayrıca, items değişkenini ve ilgili yöntemini, getProducts yöntem çağrısını kaldırın. Ürün değişkenini yapıcıya yerleştirme. Uygulama ilk başlatıldığında ürünlerin İnternet'ten yalnızca bir kez alınmasına izin verecektir.

class MyHomePage extends StatelessWidget { 
   final String title; 
   final Future<ListList<Product>> products; 
   MyHomePage({Key key, this.title, this.products}) : super(key: key); 
   ...
  • Yukarıdaki değişiklikleri barındırmak için Uygulamam widget'ının oluşturma yöntemindeki ana sayfa seçeneğini (MyHomePage) değiştirin -

home: MyHomePage(title: 'Product Navigation demo home page', products: products),
  • Ana işlevi Gelecek <Ürün> bağımsız değişkenlerini içerecek şekilde değiştirin -

void main() => runApp(MyApp(fetchProduct()));
  • Ana sayfada ürün listesini oluşturmak için yeni bir pencere öğesi, ProductBoxList oluşturun.

class ProductBoxList extends StatelessWidget { 
   final List<Product> items;
   ProductBoxList({Key key, this.items}); 
   
   @override 
   Widget build(BuildContext context) {
      return ListView.builder(
         itemCount: items.length,
         itemBuilder: (context, index) {
            return GestureDetector(
               child: ProductBox(item: items[index]), 
               onTap: () {
                  Navigator.push(
                     context, MaterialPageRoute(
                        builder: (context) =gt; ProductPage(item: items[index]), 
                     ), 
                  ); 
               }, 
            ); 
         }, 
      ); 
   } 
}

Ürünü listelemek için Navigasyon uygulamasında kullanılan konseptin aynısını kullandığımıza dikkat edin, tek fark, List <Product> türündeki ürünleri (nesneyi) ileterek ayrı bir pencere öğesi olarak tasarlanmasıdır.

  • Son olarak, normal yöntem çağrısı yerine Gelecek seçeneğini kullanarak ürün bilgilerini almak için MyHomePage küçük aracının oluşturma yöntemini değiştirin.

Widget build(BuildContext context) { 
   return Scaffold(
      appBar: AppBar(title: Text("Product Navigation")),
      body: Center(
         child: FutureBuilder<List<Product>>(
            future: products, builder: (context, snapshot) {
               if (snapshot.hasError) print(snapshot.error); 
               return snapshot.hasData ? ProductBoxList(items: snapshot.data)
               
               // return the ListView widget : 
               Center(child: CircularProgressIndicator()); 
            }, 
         ), 
      )
   ); 
}
  • Burada, widget'ı oluşturmak için FutureBuilder widget'ını kullandığımızı unutmayın. FutureBuilder, verileri gelecekteki özelliğinden (Gelecek <List <Product>> türünde) almaya çalışacaktır. Gelecekteki özellik veri döndürürse, pencere öğesini ProductBoxList kullanarak oluşturur, aksi takdirde bir hata atar.

  • Main.dart'ın tam kodu aşağıdaki gibidir -

import 'package:flutter/material.dart'; 
import 'dart:async'; 
import 'dart:convert'; 
import 'package:http/http.dart' as http; 
import 'Product.dart'; 

void main() => runApp(MyApp(products: fetchProducts())); 

List<Product> parseProducts(String responseBody) { 
   final parsed = json.decode(responseBody).cast<Map<String, dynamic>>(); 
   return parsed.map<Product>((json) => Product.fromMap(json)).toList(); 
} 
Future<List<Product>> fetchProducts() async { 
   final response = await http.get('http://192.168.1.2:8000/products.json'); 
   if (response.statusCode == 200) { 
      return parseProducts(response.body); 
   } else { 
      throw Exception('Unable to fetch products from the REST API'); 
   } 
}
class MyApp extends StatelessWidget {
   final Future<List<Product>> products; 
   MyApp({Key key, this.products}) : super(key: key); 
   
   // This widget is the root of your application. 
   @override 
   Widget build(BuildContext context) {
      return MaterialApp(
         title: 'Flutter Demo', 
         theme: ThemeData( 
            primarySwatch: Colors.blue, 
         ), 
         home: MyHomePage(title: 'Product Navigation demo home page', products: products), 
      ); 
   }
}
class MyHomePage extends StatelessWidget { 
   final String title; 
   final Future<List<Product>> products; 
   MyHomePage({Key key, this.title, this.products}) : super(key: key); 
   
   // final items = Product.getProducts();
   @override 
   Widget build(BuildContext context) { 
      return Scaffold(
         appBar: AppBar(title: Text("Product Navigation")), 
         body: Center(
            child: FutureBuilder<List<Product>>(
               future: products, builder: (context, snapshot) {
                  if (snapshot.hasError) print(snapshot.error); 
                  return snapshot.hasData ? ProductBoxList(items: snapshot.data) 
                  
                  // return the ListView widget : 
                  Center(child: CircularProgressIndicator()); 
               },
            ),
         )
      );
   }
}
class ProductBoxList extends StatelessWidget {
   final List<Product> items; 
   ProductBoxList({Key key, this.items}); 
   
   @override 
   Widget build(BuildContext context) {
      return ListView.builder(
         itemCount: items.length, 
         itemBuilder: (context, index) { 
            return GestureDetector( 
               child: ProductBox(item: items[index]), 
               onTap: () { 
                  Navigator.push(
                     context, MaterialPageRoute( 
                        builder: (context) => ProductPage(item: items[index]), 
                     ), 
                  ); 
               }, 
            ); 
         }, 
      ); 
   } 
} 
class ProductPage extends StatelessWidget { 
   ProductPage({Key key, this.item}) : super(key: key); 
   final Product item; 
   @override 
   Widget build(BuildContext context) {
      return Scaffold(
         appBar: AppBar(title: Text(this.item.name),), 
         body: Center( 
            child: Container(
               padding: EdgeInsets.all(0), 
               child: Column( 
                  mainAxisAlignment: MainAxisAlignment.start, 
                  crossAxisAlignment: CrossAxisAlignment.start, 
                  children: <Widget>[
                     Image.asset("assets/appimages/" + this.item.image), 
                     Expanded( 
                        child: Container( 
                           padding: EdgeInsets.all(5), 
                           child: Column( 
                              mainAxisAlignment: MainAxisAlignment.spaceEvenly, 
                              children: <Widget>[ 
                                 Text(this.item.name, style: 
                                    TextStyle(fontWeight: FontWeight.bold)), 
                                 Text(this.item.description), 
                                 Text("Price: " + this.item.price.toString()), 
                                 RatingBox(), 
                              ], 
                           )
                        )
                     ) 
                  ]
               ), 
            ), 
         ), 
      ); 
   } 
}
class RatingBox extends StatefulWidget { 
   @override 
   _RatingBoxState createState() =>_RatingBoxState(); 
} 
class _RatingBoxState extends State<RatingBox> { 
   int _rating = 0; 
   void _setRatingAsOne() {
      setState(() { 
         _rating = 1; 
      }); 
   }
   void _setRatingAsTwo() {
      setState(() {
         _rating = 2; 
      }); 
   }
   void _setRatingAsThree() { 
      setState(() {
         _rating = 3; 
      }); 
   }
   Widget build(BuildContext context) {
      double _size = 20; 
      print(_rating); 
      return Row(
         mainAxisAlignment: MainAxisAlignment.end, 
         crossAxisAlignment: CrossAxisAlignment.end, 
         mainAxisSize: MainAxisSize.max, 
         
         children: <Widget>[
            Container(
               padding: EdgeInsets.all(0), 
               child: IconButton( 
                  icon: (
                     _rating >= 1 
                     ? Icon(Icons.star, ize: _size,) 
                     : Icon(Icons.star_border, size: _size,)
                  ), 
                  color: Colors.red[500], onPressed: _setRatingAsOne, iconSize: _size, 
               ), 
            ), 
            Container(
               padding: EdgeInsets.all(0), 
               child: IconButton(
                  icon: (
                     _rating >= 2 
                     ? Icon(Icons.star, size: _size,) 
                     : Icon(Icons.star_border, size: _size, )
                  ), 
                  color: Colors.red[500], 
                  onPressed: _setRatingAsTwo, 
                  iconSize: _size, 
               ), 
            ), 
            Container(
               padding: EdgeInsets.all(0), 
               child: IconButton(
                  icon: (
                     _rating >= 3 ? 
                     Icon(Icons.star, size: _size,)
                     : Icon(Icons.star_border, size: _size,)
                  ), 
                  color: Colors.red[500], 
                  onPressed: _setRatingAsThree, 
                  iconSize: _size, 
               ), 
            ), 
         ], 
      ); 
   } 
}
class ProductBox extends StatelessWidget {
   ProductBox({Key key, this.item}) : super(key: key); 
   final Product item; 
   
   Widget build(BuildContext context) {
      return Container(
         padding: EdgeInsets.all(2), height: 140, 
         child: Card(
            child: Row( 
               mainAxisAlignment: MainAxisAlignment.spaceEvenly, 
               children: <Widget>[
                  Image.asset("assets/appimages/" + this.item.image), 
                  Expanded( 
                     child: Container( 
                        padding: EdgeInsets.all(5), 
                        child: Column( 
                           mainAxisAlignment: MainAxisAlignment.spaceEvenly, 
                           children: <Widget>[ 
                              Text(this.item.name, style:TextStyle(fontWeight: FontWeight.bold)), 
                              Text(this.item.description), 
                              Text("Price: " + this.item.price.toString()), 
                              RatingBox(), 
                           ], 
                        )
                     )
                  )
               ]
            ), 
         )
      ); 
   } 
}

Sonunda sonucu görmek için uygulamayı çalıştırın. Uygulama kodlanırken girilen yerel, statik veriler yerine verilerin İnternet'ten olması dışında Navigasyon örneğimizle aynı olacaktır .