Http Request Service with Flutter

Yakup BASER
3 min readSep 12, 2021

Hello, I have prepared an article about how to create secure http requests with Flutter.

PROBLEM:
Normally, Get-Post operations with flutter are explained in the link https://flutter.dev/docs/cookbook/networking/send-data.
But we are not OK with the returning variable reponse. First json parse and then we need to convert it to our own model. But can all processes be coded in a single method? The answer is Yes!
We will look for the solution to it in this article.

SOLUTION:
First of all, we will create a request method. The method must take a generic type because it doesn’t know our data model. To explain this better, let’s assume the name of our model as User. The return value from the our request method can be User or List<User>. So it must be a generic type. Finally we send an instance of our model to our request method. So we can use methods such as toJson, fromJson belonging to our model. In addition, we do not leave out to extend our model from an abstract class that contains the toJson and fromJson methods.

CODES:
network_manager.dart

import 'dart:convert';import 'inetwork_model.dart';import 'package:http/http.dart' as http;enum RequestTypes { GET, POST }class NetworkManager {static NetworkManager? _networkManager;factory NetworkManager() {if (_networkManager == null) {_networkManager = NetworkManager._internal();return _networkManager!;} else {return _networkManager!;}}NetworkManager._internal();static const END_POINT = "https://jsonplaceholder.typicode.com/";
/// You can create a request with `GET` and `POST` methods.
////// `R` should be your response model or your response model list, like as `MyModel` or `List<MyModel>`////// `T` should be your response model, like as `MyModel`////// [path] is your request directory. You don't need to add `/` when adding [path].////// [method] should be `RequestTypes.GET` or `RequestTypes.POST`////// [parseModel] should be an instance from your model which in your response, like as `MyModel()`////// [queryParameters] should be an `Object` and contains your parameters, like as `{"id": 26}`////// [headers] You can add http request headers here. It has default `json` content-type////// It returns `MyModel` or `List<MyModel>` or `null`////// GET Method example:/// ```dart/// var myUser = await request<List<MyModel>, MyModel>(/// path: "todos",/// method: RequestTypes.GET,/// parseModel: MyModel(),/// );/// ```////// POST Method example:/// ```dart/// var myUser = await request<MyModel, MyModel>(/// path: 'posts',/// method: RequestTypes.POST,/// parseModel: MyModel(),/// queryParameters: {"title": "foo", "body": "bar", "userId": 1},/// );/// ```Future<R?> request<R, T extends INetworkModel>({required String path,required RequestTypes method,required T parseModel,Map<String, dynamic>? queryParameters,Map<String, String>? headers}) async {if (headers == null) {headers = {'Content-Type': 'application/json; charset=UTF-8'};}if (headers["Content-Type"] == null) {headers["Content-Type"] = 'application/json; charset=UTF-8';}http.Response? response;var endUri = Uri.parse(END_POINT + path);if (method == RequestTypes.GET) {try {response = await http.get(endUri, headers: headers);} catch (e) {print(e.toString());return null;}if (response.statusCode == 200 || response.statusCode == 201) {return _parser<R, T>(parseModel, jsonDecode(response.body));}return null;} else {try {response = await http.post(endUri,body: jsonEncode(queryParameters), headers: headers);} catch (e) {print(e.toString());return null;}if (response.statusCode == 200 || response.statusCode == 201) {}return _parser<R, T>(parseModel, jsonDecode(response.body));}}}R? _parser<R, T>(INetworkModel model, dynamic data) {if (data is List) {return data.map((e) => model.fromJson(e)).toList().cast<T>() as R?;} else if (data is Map) {return model.fromJson(data as Map<String, dynamic>) as R?;}return data as R?;}

inetwork_model.dart:

abstract class INetworkModel<T> {Map<String, dynamic> toJson();T fromJson(Map<String, dynamic> json);}

Using the request method, which returns a User model:

final networkManager = NetworkManager();User user = await networkManager.request<User, User>(path: "todos/1", method: RequestTypes.GET, parseModel: User());debugPrint(user.toString());

Usage of request method that returns List<User>:

final networkManager = NetworkManager();List<User> userList = await networkManager.request<List<User>, User>(path: "todos", method: RequestTypes.GET, parseModel: User());debugPrint(userList.toString());

NOTES:
I used https://jsonplaceholder.typicode.com/ for Get-Post operations.
I used the http package for http requests. When creating our model
I used the json_serializable package. You can find documentation on the Internet on the use of this package.
I created the Network Manager class using LazySingleton.

GITHUB:
https://github.com/yakupbaser/newhttprequest

REFERANCES:
https://flutter.dev/docs/cookbook/networking/send-data,

https://github.com/VB10,

https://github.com/google/json_serializable.dart

--

--