Applications frequently need to perform POST
and GET
and other HTTP requests.
Flutter provides an http
package that supports making HTTP requests.
In this article, you will create an example Flutter app that uses the http
package to perform HTTP requests to display placeholder information.
To complete this tutorial, you will need:
This tutorial was verified with Flutter v1.22.2, Android SDK v30.0.2, and Android Studio v4.1.
In order to follow along with the setup, you will be creating an example Flutter app.
Once you have your environment set up for Flutter, you can run the following to create a new application:
- flutter create flutter_http_example
Navigate to the new project directory:
- cd flutter_http_example
Using flutter create
will produce a demo application that will display the number of times a button is clicked.
Open pubspec.yaml
in your code editor and add the following plugin:
dependencies:
flutter:
sdk: flutter
http: ^0.12.0+2
This is an official Flutter plugin published by dart.dev and it has a 100% health score, therefore, you can trust the reliability of this plugin.
GET
RequestsYour first task will be to create a class that you can use to interact with the API.
Open your code editor and create a http_service.dart
file in the lib
directory. Here, you will develop a new HttpService
class and add a getPosts
function:
import 'dart:convert';
import 'package:http/http.dart';
import 'post_model.dart';
class HttpService {
final String postsURL = "https://jsonplaceholder.typicode.com/posts";
Future<List<Post>> getPosts() async {
Response res = await get(postsURL);
if (res.statusCode == 200) {
List<dynamic> body = jsonDecode(res.body);
List<Post> posts = body
.map(
(dynamic item) => Post.fromJson(item),
)
.toList();
return posts;
} else {
throw "Unable to retrieve posts.";
}
}
}
In this example, you will be connecting to JSON Placeholder. This code uses the http
package’s get
on the postsURL
string.
If that request was successful, this code will return a List<Post>
using Post.fromJson
. Otherwise, an error message is thrown.
Note: HTTP status code are used to determine if a request was successful or unsuccessful. A status code of 200
represents a successful HTTP request.
Then, use your code editor to create a post_model.dart
file in the lib
directory. Here, you will develop a new Post
class:
import 'package:flutter/foundation.dart';
class Post {
final int userId;
final int id;
final String title;
final String body;
Post({
this.userId,
this.id,
this.title,
this.body,
});
factory Post.fromJson(Map<String, dynamic> json) {
return Post(
userId: json['userId'] as int,
id: json['id'] as int,
title: json['title'] as String,
body: json['body'] as String,
);
}
}
In order to serialize the response from JSON Placeholder, this code will return a new Post
with the fromJson
method based on a JSON Map
.
Note: In a production application, a package like json_serializable
could be used to handle the serialization automatically.
A Post
returned by JSON Placeholder will consist of a userId
, id
, title
, and body
.
Posts
Next, use your code editor to create a posts.dart
file in the lib
directory. Here, you will create a PostsPage
class which will display the Posts
that are returned from the HTTP request to JSON Placeholder:
import 'package:flutter/material.dart';
import 'http_service.dart';
import 'post_model.dart';
class PostsPage extends StatelessWidget {
final HttpService httpService = HttpService();
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Posts"),
),
body: FutureBuilder(
future: httpService.getPosts(),
builder: (BuildContext context, AsyncSnapshot<List<Post>> snapshot) {
if (snapshot.hasData) {
List<Post> posts = snapshot.data;
return ListView(
children: posts
.map(
(Post post) => ListTile(
title: Text(post.title),
subtitle: Text("${post.userId}"),
),
)
.toList(),
);
} else {
return Center(child: CircularProgressIndicator());
}
},
),
);
}
}
This code uses the FutureBuilder
widget to interact with the getPosts()
function. This allows the code to determine when the List<Post>
is ready and act accordingly.
If the snapshot.hasData
is false
, then the CircularProgressIndicator
is displayed. Otherwise, the ListTile
with post information is displayed.
In order to observe what you have so far, you will need to replace the code in main.dart
.
Open lib/main.dart
in your code editor and modify it to use PostsPage
:
import 'package:flutter/material.dart';
import 'posts.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
Widget build(BuildContext context) {
return MaterialApp(
title: 'HTTP',
debugShowCheckedModeBanner: false,
theme: ThemeData(
primarySwatch: Colors.blue,
visualDensity: VisualDensity.adaptivePlatformDensity,
),
home: PostsPage(),
);
}
}
Compile your code and have it run in an emulator:
You should observe a list of post titles and user ids returned by JSON Placeholder.
Note: The titles will be excerpts from Lorem Ipsum which is frequently used as placeholder text.
The next step is to create a detail page with more information about the post when a user clicks on a post title.
PostDetail
If the user taps on the post, your app should navigate the user away to a PostDetail
page.
Use your code editor to create a post_detail.dart
file in the lib
directory. Here, you will create a PostDetail
class which will display an individual Post
:
import 'package:flutter/material.dart';
import 'post_model.dart';
class PostDetail extends StatelessWidget {
final Post post;
PostDetail({ this.post});
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(post.title),
),
body: SingleChildScrollView(
child: Padding(
padding: const EdgeInsets.all(12.0),
child: Column(
children: <Widget>[
Card(
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
ListTile(
title: Text("Title"),
subtitle: Text(post.title),
),
ListTile(
title: Text("ID"),
subtitle: Text("${post.id}"),
),
ListTile(
title: Text("Body"),
subtitle: Text(post.body),
),
ListTile(
title: Text("User ID"),
subtitle: Text("${post.userId}"),
),
],
),
),
],
),
),
)
);
}
}
This code will display the title
, id
, body
, and userId
.
In order to observe what you have so far, you will need to modify posts.dart
to support post_detail.dart
:
import 'package:flutter/material.dart';
import 'http_service.dart';
import 'post_detail.dart';
import 'post_model.dart';
class PostsPage extends StatelessWidget {
final HttpService httpService = HttpService();
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Posts"),
),
body: FutureBuilder(
future: httpService.getPosts(),
builder: (BuildContext context, AsyncSnapshot<List<Post>> snapshot) {
if (snapshot.hasData) {
List<Post> posts = snapshot.data;
return ListView(
children: posts
.map(
(Post post) => ListTile(
title: Text(post.title),
subtitle: Text("${post.userId}"),
onTap: () => Navigator.of(context).push(
MaterialPageRoute(
builder: (context) => PostDetail(
post: post,
),
),
),
),
)
.toList(),
);
} else {
return Center(child: CircularProgressIndicator());
}
},
),
);
}
}
Compile your code and have it run in an emulator:
The next step is to add the ability to remove a post by deleting it.
DELETE
RequestsAnother example of an HTTP request is the use of the DELETE
method.
Revisit http_service.dart
in your code editor and create a deletePost(int id)
method:
import 'dart:convert';
import 'package:http/http.dart';
import 'post_model.dart';
class HttpService {
final String postsURL = "https://jsonplaceholder.typicode.com/posts";
// ...
Future<void> deletePost(int id) async {
Response res = await delete("$postsURL/$id");
if (res.statusCode == 200) {
print("DELETED");
} else {
throw "Unable to delete post.";
}
}
}
Revisit post_detail.dart
in your code editor and add an IconButton
to the actions
array within the AppBar
. When the icon is pressed, the associated post should be deleted:
import 'package:flutter/material.dart';
import 'http_service.dart';
import 'post_model.dart';
class PostDetail extends StatelessWidget {
final HttpService httpService = HttpService();
final Post post;
PostDetail({ this.post});
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(post.title),
actions: <Widget>[
IconButton(
icon: Icon(Icons.delete),
onPressed: () async {
await httpService.deletePost(post.id);
Navigator.of(context).pop();
},
)
],
),
// ...
);
}
}
Compile your code and have it run in an emulator.
When you visit a post detail page, you will see a Delete icon button in the AppBar. Pressing on the button will print a message in the console:
Outputflutter: DELETED
This will represent a delete request. Due to the limitations of JSON Placeholder and this example application, the post will not actually be deleted.
In this article, you learned how to interact with the Flutter http
package. This allowed you to GET
a list of posts and DELETE
an individual post.
Similar operations such as post
, put
, patch
, and so on are also available. Consult the official documentation for more information.
Thanks for learning with the DigitalOcean Community. Check out our offerings for compute, storage, networking, and managed databases.
This textbox defaults to using Markdown to format your answer.
You can type !ref in this text area to quickly search our full set of tutorials, documentation & marketplace offerings and insert the link!
Awesome content