Don't miss ourDecember livestream, with updates on Flutter and live Q&A!
Send data to the internet
How to use the http package to send data over the internet.
Sending data to the internet is necessary for most apps. Thehttp package has got that covered, too.
This recipe uses the following steps:
- Add the
httppackage. - Send data to a server using the
httppackage. - Convert the response into a custom Dart object.
- Get a
titlefrom user input. - Display the response on screen.
1. Add thehttp package
# To add thehttp package as a dependency, runflutter pub add:
flutter pub add httpImport thehttp package.
import'package:http/http.dart'ashttp; If you are deploying to Android, edit yourAndroidManifest.xml file to add the Internet permission.
<!-- Required to fetch data from the internet.--><uses-permission android:name="android.permission.INTERNET" /> Likewise, if you are deploying to macOS, edit yourmacos/Runner/DebugProfile.entitlements andmacos/Runner/Release.entitlements files to include the network client entitlement.
<!-- Required to fetch data from the internet.--><key>com.apple.security.network.client</key><true/>2. Sending data to server
# This recipe covers how to create anAlbum by sending an album title to theJSONPlaceholder using thehttp.post() method.
Importdart:convert for access tojsonEncode to encode the data:
import'dart:convert';Use thehttp.post() method to send the encoded data:
Future<http.Response>createAlbum(Stringtitle){returnhttp.post(Uri.parse('https://jsonplaceholder.typicode.com/albums'),headers:<String,String>{'Content-Type':'application/json; charset=UTF-8',},body:jsonEncode(<String,String>{'title':title}),);} Thehttp.post() method returns aFuture that contains aResponse.
Futureis a core Dart class for working with asynchronous operations. A Future object represents a potential value or error that will be available at some time in the future.- The
http.Responseclass contains the data received from a successful http call. - The
createAlbum()method takes an argumenttitlethat is sent to the server to create anAlbum.
3. Convert thehttp.Response to a custom Dart object
# While it's easy to make a network request, working with a rawFuture<http.Response> isn't very convenient. To make your life easier, convert thehttp.Response into a Dart object.
Create an Album class
# First, create anAlbum class that contains the data from the network request. It includes a factory constructor that creates anAlbum from JSON.
Converting JSON withpattern matching is only one option. For more information, see the full article onJSON and serialization.
classAlbum{finalintid;finalStringtitle;constAlbum({requiredthis.id,requiredthis.title});factoryAlbum.fromJson(Map<String,dynamic>json){returnswitch(json){{'id':intid,'title':Stringtitle}=>Album(id:id,title:title),_=>throwconstFormatException('Failed to load album.'),};}}Convert thehttp.Response to anAlbum
# Use the following steps to update thecreateAlbum() function to return aFuture<Album>:
- Convert the response body into a JSON
Mapwith thedart:convertpackage. - If the server returns a
CREATEDresponse with a status code of 201, then convert the JSONMapinto anAlbumusing thefromJson()factory method. - If the server doesn't return a
CREATEDresponse with a status code of 201, then throw an exception. (Even in the case of a "404 Not Found" server response, throw an exception. Do not returnnull. This is important when examining the data insnapshot, as shown below.)
Future<Album>createAlbum(Stringtitle)async{finalresponse=awaithttp.post(Uri.parse('https://jsonplaceholder.typicode.com/albums'),headers:<String,String>{'Content-Type':'application/json; charset=UTF-8',},body:jsonEncode(<String,String>{'title':title}),);if(response.statusCode==201){// If the server did return a 201 CREATED response,// then parse the JSON.returnAlbum.fromJson(jsonDecode(response.body)asMap<String,dynamic>);}else{// If the server did not return a 201 CREATED response,// then throw an exception.throwException('Failed to create album.');}}Hooray! Now you've got a function that sends the title to a server to create an album.
4. Get a title from user input
# Next, create aTextField to enter a title and aElevatedButton to send data to server. Also define aTextEditingController to read the user input from aTextField.
When theElevatedButton is pressed, the_futureAlbum is set to the value returned bycreateAlbum() method.
Column(mainAxisAlignment:MainAxisAlignment.center,children:<Widget>[TextField(controller:_controller,decoration:constInputDecoration(hintText:'Enter Title'),),ElevatedButton(onPressed:(){setState((){_futureAlbum=createAlbum(_controller.text);});},child:constText('Create Data'),),],) On pressing theCreate Data button, make the network request, which sends the data in theTextField to the server as aPOST request. The Future,_futureAlbum, is used in the next step.
5. Display the response on screen
# To display the data on screen, use theFutureBuilder widget. TheFutureBuilder widget comes with Flutter and makes it easy to work with asynchronous data sources. You must provide two parameters:
- The
Futureyou want to work with. In this case, the future returned from thecreateAlbum()function. - A
builderfunction that tells Flutter what to render, depending on the state of theFuture: loading, success, or error.
Note thatsnapshot.hasData only returnstrue when the snapshot contains a non-null data value. This is why thecreateAlbum() function should throw an exception even in the case of a "404 Not Found" server response. IfcreateAlbum() returnsnull, thenCircularProgressIndicator displays indefinitely.
FutureBuilder<Album>(future:_futureAlbum,builder:(context,snapshot){if(snapshot.hasData){returnText(snapshot.data!.title);}elseif(snapshot.hasError){returnText('${snapshot.error}');}returnconstCircularProgressIndicator();},)Complete example
#import'dart:async';import'dart:convert';import'package:flutter/material.dart';import'package:http/http.dart'ashttp;Future<Album>createAlbum(Stringtitle)async{finalresponse=awaithttp.post(Uri.parse('https://jsonplaceholder.typicode.com/albums'),headers:<String,String>{'Content-Type':'application/json; charset=UTF-8',},body:jsonEncode(<String,String>{'title':title}),);if(response.statusCode==201){// If the server did return a 201 CREATED response,// then parse the JSON.returnAlbum.fromJson(jsonDecode(response.body)asMap<String,dynamic>);}else{// If the server did not return a 201 CREATED response,// then throw an exception.throwException('Failed to create album.');}}classAlbum{finalintid;finalStringtitle;constAlbum({requiredthis.id,requiredthis.title});factoryAlbum.fromJson(Map<String,dynamic>json){returnswitch(json){{'id':intid,'title':Stringtitle}=>Album(id:id,title:title),_=>throwconstFormatException('Failed to load album.'),};}}voidmain(){runApp(constMyApp());}classMyAppextendsStatefulWidget{constMyApp({super.key});@overrideState<MyApp>createState(){return_MyAppState();}}class_MyAppStateextendsState<MyApp>{finalTextEditingController_controller=TextEditingController();Future<Album>?_futureAlbum;@overrideWidgetbuild(BuildContextcontext){returnMaterialApp(title:'Create Data Example',theme:ThemeData(colorScheme:ColorScheme.fromSeed(seedColor:Colors.deepPurple),),home:Scaffold(appBar:AppBar(title:constText('Create Data Example')),body:Container(alignment:Alignment.center,padding:constEdgeInsets.all(8),child:(_futureAlbum==null)?buildColumn():buildFutureBuilder(),),),);}ColumnbuildColumn(){returnColumn(mainAxisAlignment:MainAxisAlignment.center,children:<Widget>[TextField(controller:_controller,decoration:constInputDecoration(hintText:'Enter Title'),),ElevatedButton(onPressed:(){setState((){_futureAlbum=createAlbum(_controller.text);});},child:constText('Create Data'),),],);}FutureBuilder<Album>buildFutureBuilder(){returnFutureBuilder<Album>(future:_futureAlbum,builder:(context,snapshot){if(snapshot.hasData){returnText(snapshot.data!.title);}elseif(snapshot.hasError){returnText('${snapshot.error}');}returnconstCircularProgressIndicator();},);}}Unless stated otherwise, the documentation on this site reflects Flutter 3.38.1. Page last updated on 2025-10-28.View source orreport an issue.