Upgrade & Secure Your Future with DevOps, SRE, DevSecOps, MLOps!
We spend hours on Instagram and YouTube and waste money on coffee and fast food, but won’t spend 30 minutes a day learning skills to boost our careers.
Master in DevOps, SRE, DevSecOps & MLOps!
Learn from Guru Rajesh Kumar and double your salary in just one year.
INTRODUCTION:
JSON is typically used to transmit data from a client to a server and from a server to a client. We’ll build a Flutter application in this post that can do the following things.
Display data from the server, add data, edit server data, and display data from the client. Delete the server’s data.
I believe that all of us who have used client-server data communication are familiar with these four functions, which are sometimes referred to as CRUD.
Here, the app rather than the server side is the main focus. I’ve got a phony json server ready for the server side so we can practise and learn. This is the fraudulent json link.

The endpoint list is as follows.
GET

POST

PUT

Project Creation:
Now please create a new project by name
flutter_crud_api_sample_app.

Then, we add the http dependency to the pubspec.yaml file
dependencies:
flutter:
sdk: flutter
# The following adds the Cupertino Icons font to your application.
# Use with the CupertinoIcons class for iOS style icons.
cupertino_icons: ^0.1.2
http: ^0.12.0+2
Create Class Model:
Now we need to create a model class from our endpoint response.
import ‘dart:convert’; | |
class Profile { | |
int id; | |
String name; | |
String email; | |
int age; | |
Profile({this.id = 0, this.name, this.email, this.age}); | |
factory Profile.fromJson(Map<String, dynamic> map) { | |
return Profile( | |
id: map[“id”], name: map[“name”], email: map[“email”], age: map[“age”]); | |
} | |
Map<String, dynamic> toJson() { | |
return {“id”: id, “name”: name, “email”: email, “age”: age}; | |
} | |
@override | |
String toString() { | |
return ‘Profile{id: $id, name: $name, email: $email, age: $age}’; | |
} | |
} | |
List<Profile> profileFromJson(String jsonData) { | |
final data = json.decode(jsonData); | |
return List<Profile>.from(data.map((item) => Profile.fromJson(item))); | |
} | |
String profileToJson(Profile data) { | |
final jsonData = data.toJson(); | |
return json.encode(jsonData); | |
} |
We add four fields to the model class: id, name, email, and age. Then we build a constructor with inputs based on the four fields mentioned previously. Then, in the code that follows, we create a Named Constructor.
factory Profile.fromJson(Map<String, dynamic> map) { | |
return Profile( | |
id: map[“id”], name: map[“name”], email: map[“email”], age: map[“age”]); | |
} |
When calling the Named Constructor, we are utilising the term factory, which prevents the creation of new objects. For the transition from Map to Class Model, we use Named Constructor.
Then, in the code that follows, we add a conversion function from Class Model to Map.
Map<String, dynamic> toJson() { | |
return {“id”: id, “name”: name, “email”: email, “age”: age}; | |
} |
Then, in the code that follows, we add a function to translate the API answer to our model class.
Additionally, the following code contains a function that converts model class data to JSON Format in the form of a String.
List<Profile> profileFromJson(String jsonData) { | |
final data = json.decode(jsonData); | |
return List<Profile>.from(data.map((item) => Profile.fromJson(item))); | |
} |
And a function to convert from model class to JSON Format in the form of a String in the following code.
String profileToJson(Profile data) { | |
final jsonData = data.toJson(); | |
return json.encode(jsonData); | |
} |
Develop an API Service:
To make a request to the endpoint, we must now create an API Service class.
import ‘package:flutter_crud_api_sample_app/src/model/profile.dart’; | |
import ‘package:http/http.dart’ show Client; | |
class ApiService { | |
final String baseUrl = “http://api.bengkelrobot.net:8001”; | |
Client client = Client(); | |
Future<List<Profile>> getProfiles() async { | |
final response = await client.get(“$baseUrl/api/profile”); | |
if (response.statusCode == 200) { | |
return profileFromJson(response.body); | |
} else { | |
return null; | |
} | |
} | |
} |
In the code above, we create a getProfiles function which functions to make GET requests to the endpoint
Test Class Model and API Service:
Now before we move on to creating the UI, it would be better if we first test whether the model class and API Service that we created are correct or not.
@override | |
Widget build(BuildContext context) { | |
ApiService().getProfiles().then((value) => print(“value: $value”)); | |
… | |
} |
Create the above code inside the default widget that was created when we created the project for the first time. Now try running the program and see in the logs if we get the data from the API.

Display data from the server
Create a Home Screen:
class HomeScreen extends StatefulWidget { | |
@override | |
_HomeScreenState createState() => _HomeScreenState(); | |
} | |
class _HomeScreenState extends State<HomeScreen> { | |
ApiService apiService; | |
@override | |
void initState() { | |
super.initState(); | |
apiService = ApiService(); | |
} | |
@override | |
Widget build(BuildContext context) { | |
return SafeArea( | |
child: FutureBuilder( | |
future: apiService.getProfiles(), | |
builder: (BuildContext context, AsyncSnapshot<List<Profile>> snapshot) { | |
if (snapshot.hasError) { | |
return Center( | |
child: Text( | |
“Something wrong with message: ${snapshot.error.toString()}”), | |
); | |
} else if (snapshot.connectionState == ConnectionState.done) { | |
List<Profile> profiles = snapshot.data; | |
return _buildListView(profiles); | |
} else { | |
return Center( | |
child: CircularProgressIndicator(), | |
); | |
} | |
}, | |
), | |
); | |
} | |
Widget _buildListView(List<Profile> profiles) { | |
return Padding( | |
padding: const EdgeInsets.symmetric(vertical: 8.0, horizontal: 16.0), | |
child: ListView.builder( | |
itemBuilder: (context, index) { | |
Profile profile = profiles[index]; | |
return Padding( | |
padding: const EdgeInsets.only(top: 8.0), | |
child: Card( | |
child: Padding( | |
padding: const EdgeInsets.all(16.0), | |
child: Column( | |
crossAxisAlignment: CrossAxisAlignment.start, | |
children: <Widget>[ | |
Text( | |
profile.name, | |
style: Theme.of(context).textTheme.title, | |
), | |
Text(profile.email), | |
Text(profile.age.toString()), | |
Row( | |
mainAxisAlignment: MainAxisAlignment.end, | |
children: <Widget>[ | |
FlatButton( | |
onPressed: () { | |
// TODO: do something in here | |
}, | |
child: Text( | |
“Delete”, | |
style: TextStyle(color: Colors.red), | |
), | |
), | |
FlatButton( | |
onPressed: () { | |
// TODO: do something in here | |
}, | |
child: Text( | |
“Edit”, | |
style: TextStyle(color: Colors.blue), | |
), | |
), | |
], | |
), | |
], | |
), | |
), | |
), | |
); | |
}, | |
itemCount: profiles.length, | |
), | |
); | |
} | |
} |

To make the code easier to read, we isolate the TextField widget (in the form of a method) in the aforementioned code.
Throughout form_add_screen.dart To publish data to the API, we add code inside the onPressed callback. So, using the logic below, we publish data to the API.
The validity of each field is first verified.
The values of each field are then taken.
Next, we include a profile for each data field.dart item
Next, we use the profileToJson () function to convert the profile.dart object into a json form.
Here is the code that completes the task.