{"id":19823,"date":"2020-12-04T13:10:40","date_gmt":"2020-12-04T13:10:40","guid":{"rendered":"http:\/\/www.devopsschool.com\/blog\/?p=19823"},"modified":"2020-12-05T07:30:14","modified_gmt":"2020-12-05T07:30:14","slug":"crud-using-api-in-flutter-part-1","status":"publish","type":"post","link":"https:\/\/www.devopsschool.com\/blog\/crud-using-api-in-flutter-part-1\/","title":{"rendered":"CRUD  USING API IN Flutter (Part 1)"},"content":{"rendered":"\n<p><strong>INTRODUCTION:<\/strong><\/p>\n\n\n\n<p>In general, the use of JSON is used to communicate data from client to server and from server to client. In this article we are going to create a Flutter application that can perform the following functions.<br>(I)Display data from the server<br>(II)Add data to server<br>(III)Edit data to server<br>(IV)Delete data from server<br>I think these four functions are common to all of us who have made data communication from client to server or we often know the four functions as CRUD. Our focus here is on the app side not the server side. For the server side, I have prepared a fake json server that we can test to learn. Here&#8217;s the fake json link.<\/p>\n\n\n\n<p><a href=\"http:\/\/api.bengkelrobot.net:8001\/api\/profile\" target=\"_blank\" rel=\"noopener\">http:\/\/api.bengkelrobot.net:8001\/api\/profile<\/a><\/p>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"https:\/\/miro.medium.com\/max\/1472\/1*PNweFSn0sxxYc6OEImjdsA.png\" alt=\"Image for post\" \/><\/figure>\n\n\n\n<pre id=\"tw-target-text\" class=\"wp-block-preformatted\">As for the endpoint list is as follows.\n\n<strong>GET<\/strong>\n<a href=\"http:\/\/api.bengkelrobot.net:8001\/posts\" target=\"_blank\" rel=\"noopener\">http:\/\/api.bengkelrobot.net:8001\/<\/a>api\/profile\n\n<img decoding=\"async\" src=\"https:\/\/miro.medium.com\/max\/1472\/1*BpgAlirl08kYN2tSdX6DlA.png\" alt=\"Image for post\"><\/pre>\n\n\n\n<p><strong>POST<\/strong><\/p>\n\n\n\n<p><a href=\"http:\/\/api.bengkelrobot.net:8001\/api\/profile\" target=\"_blank\" rel=\"noopener\">http:\/\/api.bengkelrobot.net:8001\/api\/profile<\/a><\/p>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"https:\/\/miro.medium.com\/max\/1472\/1*8JTEiOjw9hperrGPgSedoA.png\" alt=\"Image for post\" \/><\/figure>\n\n\n\n<p><strong>PUT<\/strong><\/p>\n\n\n\n<p><a href=\"http:\/\/api.bengkelrobot.net:8001\/api\/profile\/:id\" target=\"_blank\" rel=\"noopener\">http:\/\/api.bengkelrobot.net:8001\/api\/profile\/:id<\/a><\/p>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"https:\/\/miro.medium.com\/max\/1472\/1*-cQOd38WkVcHoM35OwjVNQ.png\" alt=\"Image for post\" \/><\/figure>\n\n\n\n<p><strong>Project Creation:<\/strong><br>Now please create a new project by name<br>flutter_crud_api_sample_app.<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"https:\/\/miro.medium.com\/max\/912\/1*BKgJeLYPTcTZ4Q43iC9qbA.png\" alt=\"Image for post\" \/><\/figure>\n\n\n\n<p>Then, we add the http dependency to the pubspec.yaml file<\/p>\n\n\n\n<p><strong>dependencies<\/strong>:<br><strong>flutter<\/strong>:<br><strong>sdk<\/strong>: flutter<\/p>\n\n\n\n<p><em># The following adds the Cupertino Icons font to your application.<br># Use with the CupertinoIcons class for iOS style icons.<br><\/em><strong>cupertino_icons<\/strong>: ^0.1.2<\/p>\n\n\n\n<p><strong>http<\/strong>: ^0.12.0+2<\/p>\n\n\n\n<p><\/p>\n\n\n\n<p><strong>Craete Class Model:<\/strong><br>Now we need to create a model class from our endpoint response.<\/p>\n\n\n\n<p><strong>import <\/strong>&#8216;dart:convert&#8217;;<\/p>\n\n\n\n<p><strong>class <\/strong>Profile {<br>int id;<br>String name;<br>String email;<br>int age;<\/p>\n\n\n\n<p>Profile({<strong>this<\/strong>.id = 0, <strong>this<\/strong>.name, <strong>this<\/strong>.email, <strong>this<\/strong>.age});<\/p>\n\n\n\n<p><strong>factory <\/strong>Profile.fromJson(Map&lt;String, <strong>dynamic<\/strong>&gt; map) {<br><strong>return <\/strong>Profile(<br>id: map[&#8220;id&#8221;], name: map[&#8220;name&#8221;], email: map[&#8220;email&#8221;], age: map[&#8220;age&#8221;]);<br>}<\/p>\n\n\n\n<p>Map&lt;String, <strong>dynamic<\/strong>&gt; toJson() {<br><strong>return <\/strong>{&#8220;id&#8221;: id, &#8220;name&#8221;: name, &#8220;email&#8221;: email, &#8220;age&#8221;: age};<br>}<\/p>\n\n\n\n<p>@override<br>String toString() {<br><strong>return <\/strong>&#8216;Profile{id: $id, name: $name, email: $email, age: $age}&#8217;;<br>}<\/p>\n\n\n\n<p>}<\/p>\n\n\n\n<p>List&lt;Profile&gt; profileFromJson(String jsonData) {<br><strong>final <\/strong>data = json.decode(jsonData);<br><strong>return <\/strong>List&lt;Profile&gt;.from(data.map((item) =&gt; Profile.fromJson(item)));<br>}<\/p>\n\n\n\n<p>String profileToJson(Profile data) {<br><strong>final <\/strong>jsonData = data.toJson();<br><strong>return <\/strong>json.encode(jsonData);<br>}<\/p>\n\n\n\n<p><\/p>\n\n\n\n<p>In the model class, we create 4 fields, namely, id, name, email, and age. Then, we create a constructor with parameters according to the four fields earlier. Then, we create a Named Constructor in the following code.<\/p>\n\n\n\n<p><strong>factory <\/strong>Profile.fromJson(Map&lt;String, <strong>dynamic<\/strong>&gt; map) {<br><strong>return <\/strong>Profile(<br>id: map[&#8220;id&#8221;], name: map[&#8220;name&#8221;], email: map[&#8220;email&#8221;], age: map[&#8220;age&#8221;]);<br>}<\/p>\n\n\n\n<p>Where, we are using the keyword factory which functions so as not to create new objects when we call the Named Constructor. We use Named Constructor to convert from Map to Class Model.<br>Then, we also create a conversion method from Class Model to Map in the following code.<\/p>\n\n\n\n<p>Map&lt;String, <strong>dynamic<\/strong>&gt; toJson() {<br><strong>return <\/strong>{&#8220;id&#8221;: id, &#8220;name&#8221;: name, &#8220;email&#8221;: email, &#8220;age&#8221;: age};<br>}<\/p>\n\n\n\n<p>Then, we also create a function to convert the response from the API to our model class in the following code.<br>And a function to convert from model class to JSON Format in the form of a String in the following code.<\/p>\n\n\n\n<p>List&lt;Profile&gt; profileFromJson(String jsonData) {<br><strong>final <\/strong>data = json.decode(jsonData);<br><strong>return <\/strong>List&lt;Profile&gt;.from(data.map((item) =&gt; Profile.fromJson(item)));<br>}<\/p>\n\n\n\n<p><\/p>\n\n\n\n<pre id=\"tw-target-text\" class=\"wp-block-preformatted\">And a function to convert from model class to JSON Format in the form of a String in the following code.\n\nString profileToJson(Profile data) {\n<strong>final <\/strong>jsonData = data.toJson();\n<strong>return <\/strong>json.encode(jsonData);\n}<\/pre>\n\n\n\n<p><strong>Create API Service:<\/strong><\/p>\n\n\n\n<p>Now we need to create an API Service class that works to make a request to the endpoint<\/p>\n\n\n\n<p><strong>import <\/strong>&#8216;package:flutter_crud_api_sample_app\/src\/model\/profile.dart&#8217;;<br><strong>import <\/strong>&#8216;package:http\/http.dart&#8217; <strong>show <\/strong>Client;<\/p>\n\n\n\n<p><strong>class <\/strong>ApiService {<\/p>\n\n\n\n<p><strong>final <\/strong>String baseUrl = &#8220;http:\/\/api.bengkelrobot.net:8001&#8221;;<br>Client client = Client();<\/p>\n\n\n\n<p>Future&lt;List&lt;Profile&gt;&gt; getProfiles() <strong>async <\/strong>{<br><strong>final <\/strong>response = <strong>await <\/strong>client.get(&#8220;$baseUrl\/api\/profile&#8221;);<br><strong>if <\/strong>(response.statusCode == 200) {<br><strong>return <\/strong>profileFromJson(response.body);<br>} <strong>else <\/strong>{<br><strong>return null<\/strong>;<br>}<br>}<\/p>\n\n\n\n<p>}<\/p>\n\n\n\n<p>In the code above, we create a getProfiles function which functions to make GET requests to the endpoint<\/p>\n\n\n\n<p><\/p>\n\n\n\n<p><strong>Test Class Model and API Service:<\/strong><br>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.<\/p>\n\n\n\n<p>@override<br>Widget build(BuildContext context) {<br>ApiService().getProfiles().then((value) =&gt; print(&#8220;value: $value&#8221;));<br>&#8230;<br>}<br>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.<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"https:\/\/miro.medium.com\/max\/1419\/1*YKBHCMMTg5gHv1oZozH0vA.png\" alt=\"Image for post\" \/><\/figure>\n\n\n\n<p><strong>Display data from the server<br>Create a Home Screen:<\/strong><\/p>\n\n\n\n<p><strong>class <\/strong>HomeScreen <strong>extends <\/strong>StatefulWidget {<br>@override<br>_HomeScreenState createState() =&gt; _HomeScreenState();<br>}<\/p>\n\n\n\n<p><strong>class <\/strong>_HomeScreenState <strong>extends <\/strong>State&lt;HomeScreen&gt; {<br>ApiService apiService;<\/p>\n\n\n\n<p>@override<br><strong>void <\/strong>initState() {<br><strong>super<\/strong>.initState();<br>apiService = ApiService();<br>}<\/p>\n\n\n\n<p>@override<br>Widget build(BuildContext context) {<br><strong>return <\/strong>SafeArea(<br>child: FutureBuilder(<br>future: apiService.getProfiles(),<br>builder: (BuildContext context, AsyncSnapshot&lt;List&lt;Profile&gt;&gt; snapshot) {<br><strong>if <\/strong>(snapshot.hasError) {<br><strong>return <\/strong>Center(<br>child: Text(<br>&#8220;Something wrong with message: ${snapshot.error.toString()}&#8221;),<br>);<br>} <strong>else if <\/strong>(snapshot.connectionState == ConnectionState.done) {<br>List&lt;Profile&gt; profiles = snapshot.data;<br><strong>return <\/strong>_buildListView(profiles);<br>} <strong>else <\/strong>{<br><strong>return <\/strong>Center(<br>child: CircularProgressIndicator(),<br>);<br>}<br>},<br>),<br>);<br>}<\/p>\n\n\n\n<p>Widget _buildListView(List&lt;Profile&gt; profiles) {<br><strong>return <\/strong>Padding(<br>padding: <strong>const <\/strong>EdgeInsets.symmetric(vertical: 8.0, horizontal: 16.0),<br>child: ListView.builder(<br>itemBuilder: (context, index) {<br>Profile profile = profiles[index];<br><strong>return <\/strong>Padding(<br>padding: <strong>const <\/strong>EdgeInsets.only(top: 8.0),<br>child: Card(<br>child: Padding(<br>padding: <strong>const <\/strong>EdgeInsets.all(16.0),<br>child: Column(<br>crossAxisAlignment: CrossAxisAlignment.start,<br>children: &lt;Widget&gt;[<br>Text(<br>profile.name,<br>style: Theme.<em>of<\/em>(context).textTheme.title,<br>),<br>Text(profile.email),<br>Text(profile.age.toString()),<br>Row(<br>mainAxisAlignment: MainAxisAlignment.end,<br>children: &lt;Widget&gt;[<br>FlatButton(<br>onPressed: () {<br>\/\/ <em>TODO: do something in here<br><\/em>},<br>child: Text(<br>&#8220;Delete&#8221;,<br>style: TextStyle(color: Colors.<em>red<\/em>),<br>),<br>),<br>FlatButton(<br>onPressed: () {<br>\/\/ <em>TODO: do something in here<br><\/em>},<br>child: Text(<br>&#8220;Edit&#8221;,<br>style: TextStyle(color: Colors.<em>blue<\/em>),<br>),<br>),<br>],<br>),<br>],<br>),<br>),<br>),<br>);<br>},<br>itemCount: profiles.length,<br>),<br>);<br>}<br>}<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"https:\/\/miro.medium.com\/max\/856\/1*yZuzws106Bw0oZspQcVYkg.png\" alt=\"Image for post\" \/><\/figure>\n\n\n\n<p>In the code above, we create a separate TextField widget (in the form of a method) which is intended to make it easier to read the code.<br>In form_add_screen.dart inside the onPressed callback we write code to post data to the API. So, to post data to the API we apply the following logic.<br>We first check whether all fields are valid or not.<br>Then, we take the values \u200b\u200bof each field.<br>Then, we wrap each data field into the profile.dart object<br>Then, we change the profile.dart object to a json form by using the profileToJson () method.<br>And here&#8217;s the code that does the job.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>INTRODUCTION: In general, the use of JSON is used to communicate data from client to server and from server to client. In this article we are going to create a Flutter application that can perform the following functions.(I)Display data from the server(II)Add data to server(III)Edit data to server(IV)Delete data from serverI think these four functions&#8230;<\/p>\n","protected":false},"author":31,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_kad_post_transparent":"","_kad_post_title":"","_kad_post_layout":"","_kad_post_sidebar_id":"","_kad_post_content_style":"","_kad_post_vertical_padding":"","_kad_post_feature":"","_kad_post_feature_position":"","_kad_post_header":false,"_kad_post_footer":false,"_kad_post_classname":"","_joinchat":[],"footnotes":""},"categories":[6331,2],"tags":[6519,6203],"class_list":["post-19823","post","type-post","status-publish","format-standard","hentry","category-flutter","category-uncategorised","tag-crud","tag-flutter"],"_links":{"self":[{"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/posts\/19823","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/users\/31"}],"replies":[{"embeddable":true,"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/comments?post=19823"}],"version-history":[{"count":1,"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/posts\/19823\/revisions"}],"predecessor-version":[{"id":19824,"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/posts\/19823\/revisions\/19824"}],"wp:attachment":[{"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/media?parent=19823"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/categories?post=19823"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.devopsschool.com\/blog\/wp-json\/wp\/v2\/tags?post=19823"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}