Saturday, January 19, 2019

Flutter - GET and POST http requests

To get dynamic data in a mobile application. We need to connect with a server to get and post some data. To achieve it, we always use HTTP to perform curl requests and create a connection between applications and server at a certain period to send or receive the data request from an application to the server.

Flutter providing us http to connect a mobile application with a server to perform GET, POST and other requests. POST and GET are two most commonly used HTTP methods for request and response between the client and the server. GET method basically requests data from a specified resource, whereas Post method submits data to be processed to a specified resource.

If you are looking some advance http client to handle interceptors, logs, cache etc. Then you should try Dio http client that we have explained here: Flutter - Dio client to create Http Request

In this post,  we are going to learn about HTTP/HTTPS POST & GET Requests. We'll see, how can get data from the server with the help of a utility class that we have created to perform GET and POST in this sample. In this example, we'll get movie list from themoviedb. We have generated a testing key from here. To run the following sample we have to create it. So create it before start development. The final output of this post example will look like below. When you'll create project with the help of following steps. 




Let's start the development of this sample with the help of following steps:

Creating a new Project
1. Create a new project from File ⇒ New Flutter Project with your development IDE.

2. Open pubspec.yaml file and add following dependancies

 http: ^0.12.0
 transparent_image: ^0.1.0


3. After that open main.dart file and edit it. As we have set our theme and change debug banner property of Application. This is our main widget of the example. Here, we have created a grid list widget to display a list of search movies and we have created an instance of MovieApi() to get a list of items from the server.
main.dart
import 'dart:io'; import 'package:flutter/material.dart'; import 'package:flutter_movies/netwoklayer/movie.dart'; import 'package:flutter_movies/netwoklayer/movie_api.dart'; import 'package:transparent_image/transparent_image.dart'; void main() => runApp(new MyApp()); class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return new MaterialApp( debugShowCheckedModeBanner: false, theme: new ThemeData( primaryColor: const Color(0xFF02BB9F), primaryColorDark: const Color(0xFF167F67), accentColor: const Color(0xFFFFAD32), ), home: new MainPage(), ); } } class MainPage extends StatefulWidget { const MainPage(); @override _MainPageState createState() => new _MainPageState(); } class _MainPageState extends State<MainPage> with SingleTickerProviderStateMixin { static final GlobalKey<ScaffoldState> scaffoldKey = new GlobalKey<ScaffoldState>(); MovieApi _guestUserApi; TextEditingController _searchQuery; bool _isSearching = false; String searchQuery = "Search query"; List<Movie> files = new List(); @override void initState() { super.initState(); _guestUserApi=new MovieApi(); _searchQuery = new TextEditingController(); } void _startSearch() { print("open search box"); ModalRoute .of(context) .addLocalHistoryEntry(new LocalHistoryEntry(onRemove: _stopSearching)); setState(() { _isSearching = true; }); } void _stopSearching() { _clearSearchQuery(); setState(() { _isSearching = false; }); } void _clearSearchQuery() { print("close search box"); setState(() { _searchQuery.clear(); updateSearchQuery("Search query"); }); } Widget _buildTitle(BuildContext context) { var horizontalTitleAlignment = Platform.isIOS ? CrossAxisAlignment.center : CrossAxisAlignment.start; return new InkWell( onTap: () => scaffoldKey.currentState.openDrawer(), child: new Padding( padding: const EdgeInsets.symmetric(horizontal: 12.0), child: new Column( mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: horizontalTitleAlignment, children: <Widget>[ new Text('Seach box',style: new TextStyle(color: Colors.white),), ], ), ), ); } Widget _buildSearchField() { return new TextField( controller: _searchQuery, autofocus: true, decoration: const InputDecoration( hintText: 'Search...', border: InputBorder.none, hintStyle: const TextStyle(color: Colors.white), ), style: const TextStyle(color: Colors.white, fontSize: 16.0), onChanged: updateSearchQuery, ); } Future updateSearchQuery(String newQuery) async { setState(() { searchQuery = newQuery; }); print("search query " + newQuery); if(newQuery.length>2){ var search = await _guestUserApi.search(newQuery); setState(() { files.clear(); files.addAll(search.list); }); } } List<Widget> _buildActions() { if (_isSearching) { return <Widget>[ new IconButton( icon: new Icon(Icons.clear,color: Colors.white,), onPressed: () { if (_searchQuery == null || _searchQuery.text.isEmpty) { Navigator.pop(context); return; } _clearSearchQuery(); }, ), ]; } return <Widget>[ new IconButton( icon: const Icon(Icons.search,color: Colors.white,), onPressed: _startSearch, ), ]; } @override Widget build(BuildContext context) { return new Scaffold( key: scaffoldKey, appBar: new AppBar( leading: _isSearching ? const BackButton() : null, title: _isSearching ? _buildSearchField() : _buildTitle(context), actions: _buildActions(), ), body: new GridView.count( primary: true, crossAxisCount: 2, childAspectRatio: 0.80, children: List.generate(files.length, (index) { if(files[index].poster_path!=null){ return getStructuredGridCell(files[index].poster_path); }else{ return getStructuredGridCell("https://dummyimage.com/300/09f.png/fff"); } }), ), ); } Card getStructuredGridCell(String file) { return new Card( child: Stack( children: <Widget>[ Center(child: CircularProgressIndicator()), Center( child: FadeInImage.memoryNetwork( placeholder: kTransparentImage, image: "https://image.tmdb.org/t/p/w500"+file, ), ), ], ), ); } }




4. In the following file, we have created a method to access our network layer method. As you can see, we using a POST method to push a query to server and parsing response with the help of base model class.

movie_api.dart
import 'dart:async'; import 'package:flutter_movies/netwoklayer/basemodel.dart'; import 'package:flutter_movies/netwoklayer/networ_util.dart'; class MovieApi { NetworkUtil _netUtil = new NetworkUtil(); Future<BaseModel> search(String query) { String BASE_TOKEN_URL = NetworkUtil.BASE_URL + "search/movie"; return _netUtil.post(BASE_TOKEN_URL, body: { "api_key": "put_your_key_here", "query": query, }).then((dynamic res) { var results = new BaseModel.searchResult(res["results"]); results.status = 200; return results; }); } }
5. Now create basemodel.dart file. As we said, we use this class to create an object from the server response.
basemodel.dart
import 'package:flutter_movies/netwoklayer/movie.dart'; class BaseModel { int status; String message; String response; List<Movie> list; BaseModel.map(dynamic obj) { if (obj != null) { this.status = obj["status"]; if (status == null) { this.status = obj["status_code"]; } this.message = obj["message"]; this.response = obj["response"] != null ? obj["response"].toString() : null; } } BaseModel.searchResult(dynamic obj) { list = obj.map<Movie>((json) => new Movie.fromJson(json)).toList(); } }
6. Now create PODA class to keep fields of a movie.
movie.dart
class Movie extends Object { int id; String title; String original_title; String poster_path; Movie({ this.id, this.title, this.original_title, this.poster_path, }); factory Movie.fromJson(Map<String, dynamic> json) { return new Movie( id: json['id'] as int, title: json['title'] as String, original_title: json['original_title'] as String, poster_path: json['poster_path'] as String, ); } }
7. Here, we have our main file of this post that we were talking about. This is a network util class that we can use it anywhere to perform http request in a Flutter Application. In the following class,  we have created a method for GET and POST request. You can add other methods of http according to your requirement. In this file, we have created a field BASE_URL. It contains our base address of the server. We can append a method of server function. Like in this example, we use a search method of themoviedb to get a search result. If you going to build a big application. Then you should use this pattern to perform the server task.
network_util.dart
import 'dart:async'; import 'dart:convert'; import 'package:http/http.dart' as http; class NetworkUtil { static final BASE_URL = "https://api.themoviedb.org/3/"; static NetworkUtil _instance = new NetworkUtil.internal(); NetworkUtil.internal(); factory NetworkUtil() => _instance; final JsonDecoder _decoder = new JsonDecoder(); Future<dynamic> get(String url, {Map<String, String> headers, encoding}) { return http .get( url, headers: headers, ) .then((http.Response response) { String res = response.body; int statusCode = response.statusCode; print("API Response: " + res); if (statusCode < 200 || statusCode > 400 || json == null) { res = "{\"status\":"+ statusCode.toString() + ",\"message\":\"error\",\"response\":" + res + "}"; throw new Exception( statusCode); } return _decoder.convert(res); }); } Future<dynamic> post(String url, {Map<String, String> headers, body, encoding}) { return http .post(url, body: body, headers: headers, encoding: encoding) .then((http.Response response) { String res = response.body; int statusCode = response.statusCode; print("API Response: " + res); if (statusCode < 200 || statusCode > 400 || json == null) { res = "{\"status\":" + statusCode.toString() + ",\"message\":\"error\",\"response\":" + res + "}"; throw new Exception( statusCode); } return _decoder.convert(res); }); } }

If you have followed the article carefully, you can see the app running very smoothly as shown in the above. But if you are facing any problem or you have any quires, please feel free to ask it from below comment section.

Share:

Get it on Google Play

React Native - Start Development with Typescript

React Native is a popular framework for building mobile apps for both Android and iOS. It allows developers to write JavaScript code that ca...