Networking In Flutter : Dio & GetX State mixin | Flutter 3.3.5
What is Dio? Why choose Dio over HTTP? How to Perform CRUD operation using Dio? How to Handle Dio Errors easily? What is GetX State mixin ? — A Complete Beginners Guide 2022 🐥
Why choose Dio over HTTP ❓
If you’re looking for a quick response to this, then let me say that it’s because Dio offers more features than HTTP. Dio provides a lot of capabilities that HTTP lacks. Interceptors, Global configuration, FormData, Request Cancellation, File downloading, Timeout, and so on.
Dependency Installation 💡
Install the dependencies listed below.
Run flutter pub get
and you are ready to go.
Folder Structure 📂
It is advised that we follow a set structure when working on a large project.
dummyJSON
We will be using dummyJSON API in our example. This API provides all sorts of methods that we wanted: GET, POST, PUT, DELETE.
visit dummyJson for more info ℹ️
Api Service 🌐
To send a request to the server, we must first create a Client. A client may be thought of as a middleman who makes requests and then responds to us.
Here we can set the Base Url, Connection Timeout, Receive Timeout, and other options. As a result, we won’t have to send all of these parameters in every request.
Head over to
lib > app > data > network > service
and create an api_service.dart file in it.Create a Dio instance and assign different parameters inside the constructor as below:
- Here you will be getting an error saying, ApiUrl is not defined.
- To solve that, head over to
lib > app > constants
and create a file named app_constants.dart. - In this, we will define all the endpoints that we want to use in our application
Creating (GET, POST, PUT, DELETE) Methods 📍
Now that we’ve configured the Dio instance, it’s time to create HTTP methods.
Let’s create a GET method first inside the same ApiService class.
URL
There is only one required parameter in Get method, URL. Whenever we want to make a GET request we need to pass that path from which we want a response back.
Query Parameter
You can also define different query parameters if that is the case in your project. For example in some cases, the path could be:
https://abcapi.com/user?name=sinnoor
. Herename
is the query parameter and you can pass this parameter in queryParameter in Map format:{ 'name' : 'sinnoor' }
Options
The Options describe the HTTP request information and configuration. We can pass basic configurations like Headers, Method Type, Content-Type, Response Type, etc.
Cancel Token
You can cancel a request by using a cancel token. One token can be shared with different requests. when a token’s [cancel] method is invoked, all requests with this token will be canceled.
onReceiveProgress
This is a callback which is used to listen the progress for sending/receiving data. It has two parameters.
count → Indicates the length of the bytes that have been sent/received.
Total → Indicates the length of the response/body.
📍You don’t need to use these types of callback if you are doing a simple task. I’m just mentioning, so that you should know that it exists.
So these are the parameters that we are using in order to make a get request 👨🏻💻
We are also catching the error on SocketException, FormatException. are going to handle different errors further in this article ⚠️
Now let’s define the remaining 3 methods 💡
POST
While making GET requests we don’t pass any data usually. But when making the request like POST, PUT, DELETE we need to pass the body/data.
The parameters will remain same for all these 3 methods (POST, PUT, DELETE ) only the type of method will change (i.e _dio.post(), _dio.put(), _dio.delete() ).💡
Model Creation 👤
We need to develop a model for the data we’re obtaining from the server in order to parse it in a Dart-readable format.
user_model.dart. 👈 here you can see the model class that i created .
📍 I’ve used Dart Model Generator for creating the above models.
API Request Class 🌐
Now that we are all set to make an API request. Let’s head over to
lib > app> data > network > api
and create a user folder and inside it create auser_api.dart
file.
💡 In this, We are going to define different API request methods which will directly call the client’s method and will return the RAW data. Notice I said the methods defined in this class will return the RAW data, not the model that we created earlier.
- As you can see, the code is pretty straightforward. We are simply calling different methods of the ApiService by passing the required path/endpoint.
- As we have already defined the base URL in the ApiService , we only need to pass the rest of the Endpoint and not the full URL.
- For the POST method the required data is passed in Map format.
- For the PUT method we need an Id, which is used to update only the user that contains that Id.
- For DELETE we only need the Id of the user that we want to delete.
Controller 🛠
We will request data from the UI by triggering methods defined in the controller. And then controller will take rest of the responsibilities.
As I have said, the UserApi class only returns RAW data. Within the controller class, the RAW data is converted into the UserModel .
GetxController
comes withonInit()
andonClose()
methods. This allows us to completely avoid usingStatefulWidget
and write organised code.Create a
home_controller.dart
file insidelib > app> module > home > controller
then paste the below code.
State Mixin 🦾
Another way to handle our
UI
state is use theStateMixin<T>
. To implement it, use thewith
to add theStateMixin<T>
to your controller which allows a T model.The
change()
method ofStateMixin
changes the State whenever we want. We just have to pass the data and the status.
class HomeController extends GetxController with StateMixin<List<User>>
visit GetxStateMixin for more info ℹ️
Error Handling ⚠️
If you see the above controller I’ve used ApiException class for catching the DioError.
I just made a different class that returns the error message in human-readable form. The server error, the cancel request error, or the connection timeout message could all be the cause.
This class is very handy when you are handling errors.
Head over to
lib > data > network > servive
and create api_exception.dart class.
📍 Now you just need to pass DioError inside the fromDioError method and it will return a relavent message
final ApiException apiException = ApiException.fromDioError(e);
Bindings 🔗
To avoid declaring our dependencies in the view class, we can separate them from the view using Bindings.
To do this create a Class and extend it with Bindings. Then there is an override method
void dependencies()
which will hold the dependencies.Bindings are classes where we can declare our dependencies and then ‘bind’ them to the routes.
Building UI 📱
As you can see, the HomeView contains list of users. We will use
controller.obx()
in order to display users, When the server successfully returns a data otherwise we will show an error.Create a home_view.dart file inside
lib > app > module > home > view
and paste the code below.
Application Flow ⏳
When you first launch the app, the controller will call the fetchUsers() method to get the list of users from the API. The response will be parsed into a UserModel object and then assigned to the users variable. The users variable is an RxList, so it will automatically update the UI when the data changes.
The change() method is used to update the state of the controller. The change() method takes two parameters: the data and the status. The status can be RxStatus.success(), RxStatus.error(), or RxStatus.loading(). The status will be used to display the appropriate UI.
Wrapping Up 🤩
I hope this article has helped you understand how to use the GetX library to manage the state of your Flutter app. If you have any questions or suggestions, please leave a comment below. 😍 Thanks for reading :-)