I am getting "415 error unsupported media type" when i debug my application.
I got to know that i am missing to pass the headers in the post query.
i have used map to pass the data, please help me on how to pass the headers.
Or please provide me a example for Signup/Register in Flutter using JSON
import 'dart:async';
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
class Post {
final String 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'],
id: json['id'],
title: json['title'],
body: json['body'],
);
}
Map toMap() {
var map = new Map<String, dynamic>();
map["userId"] = userId;
map["title"] = title;
map["body"] = body;
return map;
}
}
Future<Post> createPost(String url, {Map body}) async {
return http.post(url, body: body).then((http.Response response) {
final int statusCode = response.statusCode;
if (statusCode < 200 || statusCode > 400 || json == null) {
throw new Exception("Error while fetching data");
}
return Post.fromJson(json.decode(response.body));
});
}
class MyApp extends StatelessWidget {
final Future<Post> post;
MyApp({Key key, this.post}) : super(key: key);
static final CREATE_POST_URL = 'https://jsonplaceholder.typicode.com/posts';
TextEditingController titleControler = new TextEditingController();
TextEditingController bodyControler = new TextEditingController();
#override
Widget build(BuildContext context) {
// TODO: implement build
return MaterialApp(
title: "WEB SERVICE",
theme: ThemeData(
primaryColor: Colors.deepOrange,
),
home: Scaffold(
appBar: AppBar(
title: Text('Create Post'),
),
body: new Container(
margin: const EdgeInsets.only(left: 8.0, right: 8.0),
child: new Column(
children: <Widget>[
new TextField(
controller: titleControler,
decoration: InputDecoration(
hintText: "title....", labelText: 'Post Title'),
),
new TextField(
controller: bodyControler,
decoration: InputDecoration(
hintText: "body....", labelText: 'Post Body'),
),
new RaisedButton(
onPressed: () async {
Post newPost = new Post(
userId: "123", id: 0, title: titleControler.text, body: bodyControler.text);
Post p = await createPost(CREATE_POST_URL,
body: newPost.toMap());
print(p.title);
},
child: const Text("Create"),
)
],
),
)),
);
}
}
void main() => runApp(MyApp());
Please let me know how to pass the headers in this program for the http.post
Here is the example to pass headers in http request
Future<dynamic> get(String url) async {
//Pass headers below
return http.get(url, headers: {"Authorization": "Some token"}).then(
(http.Response response) {
final int statusCode = response.statusCode;
LogUtils.d("====response ${response.body.toString()}");
if (statusCode < 200 || statusCode >= 400 || json == null) {
throw new ApiException(jsonDecode(response.body)["message"]);
}
return _decoder.convert(response.body);
});
}
And For post
http.post(url,
body: json.encode(body),
headers: { 'Content-type': 'application/json',
'Accept': 'application/json',
"Authorization": "Some token"},
encoding: encoding)
Try like this
http.post(
url,
body: body,
headers: {HttpHeaders.authorizationHeader: "Bearer " + token},
).then((http.Response response) {
});
Try this
return http.post(url,
body: jsonEncode(body),
headers: { 'Content-type': 'application/json'}
).then((http.Response response) {
final int statusCode = response.statusCode;
}
}
You just want to add headers in your post call. All headers should be in Map format
Future<Post> createPost(String url, {Map body}) async {
return http.post(url, body: body,headers: {"Authorization": "Bearer"}).then((http.Response response) {
final int statusCode = response.statusCode;
if (statusCode < 200 || statusCode > 400 || json == null) {
throw new Exception("Error while fetching data");
}
return Post.fromJson(json.decode(response.body));
});
}
Here is the complete example to pass headers in http get request.
add http dependency into punspec.yaml
dependencies:
http: ^0.13.3,
for latest:https://pub.dev/packages/http/install
in this example i'm printing the response value in console.
after that we can store the response data in to list.
import 'dart:async';
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
Future<Album> fetchAlbum() async {
final response =
await http.get(Uri.parse('Enter your url(link)'),headers: {"Enter your key here":"Enter your Header Value here"});
print("test in fetchAlbum()=> ${response.body}");
if (response.statusCode == 200) {
// If the server did return a 200 OK response,
// then parse the JSON.
return Album.fromJson(jsonDecode(response.body));
} else {
// If the server did not return a 200 OK response,
// then throw an exception.
throw Exception('Failed to load album');
}
//print('Test Func()');
}
class Album {
final int userId;
final int id;
final String title;
Album({
required this.userId,
required this.id,
required this.title,
});
factory Album.fromJson(Map<String, dynamic> json) {
return Album(
userId: json['userId'],
id: json['id'],
title: json['title'],
);
}
}
void main() => runApp(MyApp());
class MyApp extends StatefulWidget {
MyApp({Key? key}) : super(key: key);
#override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
late Future<Album> futureAlbum;
#override
void initState() {
super.initState();
futureAlbum = fetchAlbum();
print('initState()');
print('test $fetchAlbum()');
print('data ${futureAlbum}');
}
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Fetch Data Example',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: Scaffold(
appBar: AppBar(
title: Text('Fetch Data Example'),
),
body: Center(
child: FutureBuilder<Album>(
future: futureAlbum,
builder: (context, snapshot) {
if (snapshot.hasData) {
return Text(snapshot.data!.title);
} else if (snapshot.hasError) {
return Text("${snapshot.error}");
}
// By default, show a loading spinner.
return CircularProgressIndicator();
},
),
),
),
);
}
}
Related
Error message from backend appears in flutter terminal. How can I print this on the app?
I/flutter (16113): {"status":"Fail","error":{"code":1138,"message":"Kullanıcı zaten mevcut"}}
Service
class RegisterService extends ChangeNotifier {
bool isBack = false;
Future<RegisterResModel> register(RegisterReqModel data) async {
final http.Response response = await http.post(
Uri.parse("http://192.168.0.16:2526/api/v1/auths/register"),
headers: <String, String>{
'Content-Type': 'application/json; charset=UTF-8',
},
body: jsonEncode(data.toJson()));
if (response.statusCode == 200) {
isBack = true;
print(response.body);
return RegisterResModel.fromJson(json.decode(response.body));
} else {
isBack = false;
throw Exception(response.body);
}
}
}
Res Model
class RegisterResModel {
String? message;
String? status;
RegisterResModel({this.message, this.status});
RegisterResModel.fromJson(Map<String, dynamic> json) {
message = json['message'];
status = json['status'];
}
Map<String, dynamic> toJson(decode) {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['message'] = message;
data['status'] = status;
return data;
}
}
You need to add one class to store the error details.
class ErrorModel{
String? message;
int? code;
ErrorModel({this.message, this.code});
ErrorModel.fromJson(Map<String, dynamic> json) {
message = json['message'];
code = json['code'];
}
Map<String, dynamic> toJson(decode) {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['message'] = message;
data['code'] = code;
return data;
}
}
You can add this model to your own Register class.
class RegisterResModel {
String? message;
String? status;
ErrorModel? error;
RegisterResModel({this.message, this.status, this.error});
fromJson(Map<String, dynamic> json) {
message = json['message'];
status = json['status'];
error = ErrorModel.fromJson(json['error']);
}
Map<String, dynamic> toJson(decode) {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['message'] = message;
data['status'] = status;
return data;
}
}
similar to you have parse the response, you can now get the error information as well. Please check sample code as below.
class RegisterService extends ChangeNotifier {
bool isBack = false;
Future<RegisterResModel> register(RegisterReqModel data) async {
final http.Response response = await http.post(
Uri.parse("http://192.168.0.16:2526/api/v1/auths/register"),
headers: <String, String>{
'Content-Type': 'application/json; charset=UTF-8',
},
body: jsonEncode(data.toJson()));
if (response.statusCode == 200) {
isBack = true;
print(response.body);
return RegisterResModel.fromJson(json.decode(response.body));
} else {
isBack = false;
return RegisterResModel.fromJson(json.decode(response.body));
}
}
}
Now you can return register class and check for status fail or pass based on the response and show the error.
To show the error, there are multiple options like Show Alert dialog, Show snackbar. Those are listed as below
Alert dialog:
showAlertDialog(BuildContext context) {
// set up the button
Widget okButton = TextButton(
child: Text("OK"),
onPressed: () { },
);
// set up the AlertDialog
AlertDialog alert = AlertDialog(
title: Text("My title"),
content: Text("This is my message."),
actions: [
okButton,
],
);
// show the dialog
showDialog(
context: context,
builder: (BuildContext context) {
return alert;
},
);
}
Snackbar :
import 'package:flutter/material.dart';
void main() => runApp(const SnackBarDemo());
class SnackBarDemo extends StatelessWidget {
const SnackBarDemo({super.key});
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'SnackBar Demo',
home: Scaffold(
appBar: AppBar(
title: const Text('SnackBar Demo'),
),
body: const SnackBarPage(),
),
);
}
}
class SnackBarPage extends StatelessWidget {
const SnackBarPage({super.key});
#override
Widget build(BuildContext context) {
return Center(
child: ElevatedButton(
onPressed: () {
final snackBar = SnackBar(
content: const Text('Yay! A SnackBar!'),
action: SnackBarAction(
label: 'Undo',
onPressed: () {
// Some code to undo the change.
},
),
);
// Find the ScaffoldMessenger in the widget tree
// and use it to show a SnackBar.
ScaffoldMessenger.of(context).showSnackBar(snackBar);
},
child: const Text('Show SnackBar'),
),
);
}
}
You can wrap your main code in try catch block and incase it shows an exception/error, you can show a toast or snackBar to show the message.
Learn more about-
Try-catch block
toast messages
snackbar messages
You could use an Alert Dialog to ensure that the error is seen and acknowledged for whatever reason you're doing this.
I have built a page which reads the json from recipeURL and I wish for it to display the product_name value in the json file. However for some reason my future fetchData () class isn't being read as none of the text in my if else statement is being displayed. Am I missing a simple oversight here?
EDIT: The main dart file is my main screen. This is where my navbar is created. Users are redirected to other pages when they click on the corresponding icon. Im having trouble passing BarcodePage(title:title); as parameters in my main file,26th line, can be found under Class MyAppState extends State<MyApp> {
My main dart file:
import 'package:flutter/material.dart';
import 'pages/BarcodePage.dart';
import 'pages/FoodPage.dart';
import 'pages/RecipePage.dart';
import 'pages/ShoppingPage.dart';
void main() {
runApp(MaterialApp(debugShowCheckedModeBanner: false, home: MyApp()),);
}
class MyApp extends StatefulWidget {
#override
State<StatefulWidget> createState(){
return MyAppState();
}
}
class MyAppState extends State<MyApp> {
int _selectedPage =0;
final _pageOptions= [
FoodPage(),
RecipePage(),
BarcodePage(title: ,),
ShoppingPage(),
];
#override
Widget build(BuildContext context) {
return MaterialApp(
//title: 'Best B4',
theme: ThemeData(
primarySwatch: Colors.teal,),
debugShowCheckedModeBanner: false,
home: Scaffold (
appBar: AppBar(
title:Text(
'BestB4',
style: TextStyle(
fontFamily: 'PacificoRegular',
fontSize: 30,
),
),
backgroundColor: Colors.teal,
elevation: 20,
actions: [
IconButton(
icon: Icon(Icons.qr_code_2_rounded),
tooltip: 'Add item',
onPressed:(){
Navigator.push(
context,
MaterialPageRoute(builder: (context) => BarcodePage()));
},
)
],
//ONPRESSED MENU OPEN
),
body:_pageOptions[_selectedPage],
bottomNavigationBar: BottomNavigationBar(
type: BottomNavigationBarType.fixed,
backgroundColor: Colors.teal,
selectedItemColor: Colors.white,
unselectedItemColor: Colors.white70,
iconSize: 40,
selectedFontSize: 15,
unselectedFontSize: 15,
currentIndex:_selectedPage,
onTap: (int index) {
setState(() {
_selectedPage = index;
});
},
items: [
BottomNavigationBarItem(
icon:Icon(Icons.restaurant_rounded),
label: 'Food',
), //, title:Text('Food')
BottomNavigationBarItem(
icon:Icon(Icons.menu_book_rounded),
label:'Recipes',
),//, title:Text('Recipes')
BottomNavigationBarItem(
icon:Icon(Icons.add_outlined),
label:'Add',
),//, title:Text('Add')
BottomNavigationBarItem(
icon:Icon(Icons.shopping_cart_rounded),
label:'Shopping',
),//,title:Text('Shopping')
],
),
),
);
}
}
My BarcodePage dart file:
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as p;
import 'package:flutter/services.dart';
import 'package:barcode_scan2/barcode_scan2.dart';
import 'package:http/http.dart';
class BarcodePage extends StatefulWidget{
const BarcodePage({Key? key, required this.title}) : super(key: key);
final String title;
#override
_BarcodePageState createState() => _BarcodePageState();
}
var futuredata = {};
class _BarcodePageState extends State<BarcodePage> {
int counter=0;
String result= "";
Future _scanBarcode() async{
try{
ScanResult scanResult = await BarcodeScanner.scan();
String barcodeResult = scanResult.rawContent;
setState(() {
result = barcodeResult;
});
} on PlatformException catch (ex) {
if (ex.code == BarcodeScanner.cameraAccessDenied) {
setState((){
result = "CAMERA PERMISSION WAS DENIED. \n EDIT THIS IN YOUR SETTINGS";
});
}else {
setState(() {
result = "404 ERROR UNKNOWN $ex";
});
}
} on FormatException {
setState(() {
result = "SCAN AN ITEM";
});
} catch (ex){
setState(() {
result = "404 ERROR UNKNOWN $ex";
});
}
}
#override
void initState() {}
fetchmydata() async {
var request = p.Request(
'GET',
Uri.parse(
'https://world.openfoodfacts.org/api/v0/product/5060391623139.json'));
StreamedResponse response = await request.send();
if (response.statusCode == 200) {
// print(await response.stream.bytesToString());
var data = await response.stream.bytesToString();
futuredata = json.decode(data);
} else {
print(response.reasonPhrase);
}
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: Colors.teal,
title:Text('Add an item',
style: TextStyle(
fontFamily: 'Fredoka',
fontSize: 25,
),
),
),
body: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
FutureBuilder(
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.waiting)
return Center(
child: Container(
child: CircularProgressIndicator(),
height: 50,
width: 50,
),
);
else if (snapshot.connectionState == ConnectionState.done)
return ListTile(
title: Text(futuredata["product"]["product_name"].toString()),
subtitle: Text("France:" +
futuredata["product"]["product_name_en"].toString()),
);
else {
return Container(
child: CircularProgressIndicator(),
height: 50,
width: 50,
);
}
},
future: fetchmydata(),
)
],
),
floatingActionButton: FloatingActionButton.extended(
backgroundColor: Color.fromRGBO(51, 171, 160, 100),
icon: Icon(Icons.camera_alt),
label: Text("Scan"),
onPressed: _scanBarcode,
),
floatingActionButtonLocation: FloatingActionButtonLocation.centerFloat,
);
}
}
The Json file looks like this:
JSON LINK: https://world.openfoodfacts.org/api/v0/product/5060391623139.json
You can read your json like this
var futuredata = {};
var productname= futuredata["product"]["product_name"]
Your fetch method like this
fetchmydata() async {
var request = p.Request(
'GET',
Uri.parse(
'https://world.openfoodfacts.org/api/v0/product/5060391623139.json'));
StreamedResponse response = await request.send();
if (response.statusCode == 200) {
// print(await response.stream.bytesToString());
var data = await response.stream.bytesToString();
futuredata = json.decode(data);
} else {
print(response.reasonPhrase);
}
}
With model Class
SampleModel? Mymodel = null;
fetchmydata() async {
var request = p.Request(
'GET',
Uri.parse(
'https://world.openfoodfacts.org/api/v0/product/5060391623139.json'));
StreamedResponse response = await request.send();
if (response.statusCode == 200) {
// print(await response.stream.bytesToString());
var data = await response.stream.bytesToString();
futuredata = json.decode(data);
Mymodel = SampleModel.fromJson(futuredata);
} else {
print(response.reasonPhrase);
}
}
in the method we first read data from json as string or text
then we decode the string type or text from server to map type
SampleCode Dartpad live code check
import 'dart:convert';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:http/http.dart';
import 'package:http/http.dart' as p;
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
runApp(MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({Key? key, required this.title}) : super(key: key);
final String title;
#override
State<MyHomePage> createState() => _MyHomePageState();
}
var futuredata = {};
class _MyHomePageState extends State<MyHomePage> {
int _counter = 0;
#override
void initState() {}
fetchmydata() async {
var request = p.Request(
'GET',
Uri.parse(
'https://world.openfoodfacts.org/api/v0/product/5060391623139.json'));
StreamedResponse response = await request.send();
if (response.statusCode == 200) {
// print(await response.stream.bytesToString());
var data = await response.stream.bytesToString();
futuredata = json.decode(data);
} else {
print(response.reasonPhrase);
}
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(),
body: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
FutureBuilder(
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.waiting)
return Center(
child: Container(
child: CircularProgressIndicator(),
height: 50,
width: 50,
),
);
else if (snapshot.connectionState == ConnectionState.done)
return ListTile(
title: Text(futuredata["product"]["product_name"].toString()),
subtitle: Text("France:" +
futuredata["product"]["product_name_en"].toString()),
);
else {
return Container(
child: CircularProgressIndicator(),
height: 50,
width: 50,
);
}
},
future: fetchmydata(),
)
],
),
);
}
}
Sample ModelClass
///
/// Code generated by jsonToDartModel https://ashamp.github.io/jsonToDartModel/
///
class SampleModelProduct {
/*
{
"_id": "5060391623139",
"_keywords": [
"peanut"
],
"product_name": "Peanut butter",
"product_name_en": "Peanut butter",
"product_name_fr": "Peanut butter"
}
*/
String? Id;
List<String?>? Keywords;
String? productName;
String? productNameEn;
String? productNameFr;
SampleModelProduct({
this.Id,
this.Keywords,
this.productName,
this.productNameEn,
this.productNameFr,
});
SampleModelProduct.fromJson(Map<String, dynamic> json) {
Id = json['_id']?.toString();
if (json['_keywords'] != null) {
final v = json['_keywords'];
final arr0 = <String>[];
v.forEach((v) {
arr0.add(v.toString());
});
Keywords = arr0;
}
productName = json['product_name']?.toString();
productNameEn = json['product_name_en']?.toString();
productNameFr = json['product_name_fr']?.toString();
}
Map<String, dynamic> toJson() {
final data = <String, dynamic>{};
data['_id'] = Id;
if (Keywords != null) {
final v = Keywords;
final arr0 = [];
v!.forEach((v) {
arr0.add(v);
});
data['_keywords'] = arr0;
}
data['product_name'] = productName;
data['product_name_en'] = productNameEn;
data['product_name_fr'] = productNameFr;
return data;
}
}
class SampleModel {
/*
{
"code": "5060391623139",
"product": {
"_id": "5060391623139",
"_keywords": [
"peanut"
],
"product_name": "Peanut butter",
"product_name_en": "Peanut butter",
"product_name_fr": "Peanut butter"
},
"status": 1,
"status_verbose": "product found"
}
*/
String? code;
SampleModelProduct? product;
int? status;
String? statusVerbose;
SampleModel({
this.code,
this.product,
this.status,
this.statusVerbose,
});
SampleModel.fromJson(Map<String, dynamic> json) {
code = json['code']?.toString();
product = (json['product'] != null)
? SampleModelProduct.fromJson(json['product'])
: null;
status = json['status']?.toInt();
statusVerbose = json['status_verbose']?.toString();
}
Map<String, dynamic> toJson() {
final data = <String, dynamic>{};
data['code'] = code;
if (product != null) {
data['product'] = product!.toJson();
}
data['status'] = status;
data['status_verbose'] = statusVerbose;
return data;
}
}
try creating a .g.dart file using flutter packages pub run build_runner build. flutter automatically will create your binding class factory. once you have the binding classes created flutter will automatically code your binding class, including nested classes. I personally think automation is the way to handle all interactions with json from the server. The reason you want to use the future .g.dart code generator is to reduce the possibility of error and incorrect type casting.
file.dart
factory ProductView.fromJson(Map<String, dynamic> json) =>
_$ProductFromJson(json);
Map<String, dynamic> toJson() => _$ProductViewToJson(this);
file.g.dart
ProductView _$ProductViewFromJson(Map<String, dynamic> json) {
return
ProductView(
json['field1'] as int,
json['field2'] as String,
json['field3'] == null
? null
: DateTime.parse(json['field3'] as String),
);
}
Map<String, dynamic> _$ProjectViewToJson(ProductView instance) =>
<String, dynamic>{
'field1': instance.field1,
'field2': instance.field2,
'field3': instance.field3?.toIso8601String(),
};
decoding the json
var client = http.Client();
Map<String, String> headers = new HashMap();
headers['Accept'] = 'application/json';
headers['Content-Type'] = 'application/json';
headers['Authorization'] = 'Bearer $token';
var response = await client.get(url, headers: headers).timeout(_TIMEOUT);
var parsed = json.decode(response.body);
var view = ProductView.fromJson(parsed);
I'm new to flutter. I'm trying to learn about flutter rest api.
When I'm trying to post data using fullter api(using http dart package), It shows me this error.
I tried to fix it doing some changes to my code, but I still unable to fix it. Here the code that I trying to execute.
Model
import 'dart:convert';
DataModel dataModelFromJSON(String str) => DataModel.fromJson(jsonDecode(str));
String dataModelToJson(DataModel data) => json.encode(data.toJson());
class DataModel {
DataModel(
{required this.name,
required this.job,
required this.id,
required this.createdAt});
String name;
String job;
String id;
String createdAt;
factory DataModel.fromJson(Map<String, dynamic> json) => DataModel(
name: json['name'],
job: json['job'],
id: json['id'],
createdAt: json['createdAt']);
Map<String, dynamic> toJson() =>
{"name": name, "job": job, "id": id, "createdAt": createdAt};
}
main.dart
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
import 'DataModel.dart';
void main() {
runApp(
MaterialApp(
home: MyHomePage(),
),
);
}
class MyHomePage extends StatefulWidget {
#override
_MyHomePageState createState() => _MyHomePageState();
}
Future<DataModel?> submitData(String name, String job) async {
var response = await http.post(
Uri.https('reqres.in', 'api/users'),
body: {"name": name, "job": job},
);
var data = response.body;
print(data);
if (response.statusCode == 201) {
String responseString = response.body;
dataModelFromJSON(responseString);
} else
return null;
}
class _MyHomePageState extends State<MyHomePage> {
late DataModel _dataModel;
TextEditingController nameController = TextEditingController();
TextEditingController jobController = TextEditingController();
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Center(
child: Text('HTTP Post'),
),
),
body: Container(
padding: EdgeInsets.all(20.0),
child: Column(
children: [
TextField(
decoration: InputDecoration(
border: OutlineInputBorder(), hintText: 'Name'),
controller: nameController,
),
SizedBox(height: 20.0),
TextField(
decoration: InputDecoration(
border: OutlineInputBorder(), hintText: 'Job'),
controller: jobController,
),
ElevatedButton(
onPressed: () async {
String name = nameController.text;
String job = jobController.text;
DataModel? data = await submitData(name, job);
setState(() {
_dataModel = data!;
});
},
child: Text("Submit"),
)
],
),
),
);
}
}
I appreciate if somebody can help me to fix this issue.
You are not returning data in your function
add return here
return dataModelFromJSON(responseString);
Now your Function will be like this
Future<DataModel?> submitData(String name, String job) async {
var response = await http.post(
Uri.https('reqres.in', 'api/users'),
body: {"name": name, "job": job},
);
var data = response.body;
print(data);
if (response.statusCode == 201) {
String responseString = response.body;
return dataModelFromJSON(responseString);
} else
return null;
}
Remove ! from this line _dataModel = data!;
In your data model you have this
String responseString = response.body;
dataModelFromJSON(responseString);
} else
return null;
}
Which will return null if the status code of the request is not 201, which it's doing so using ! To do the null check is what's causing the error.
I'm currently working on app to fetch data through my API but when i satrt it it throwing the error
**FlutterError: List is not a subtype of type Map<String, dynamic> **.
Data through my rest API -
{
"author": {
"username": "jhinku",
"first_name": "jhinku",
"last_name": "mamoni"
},
"content": "💔💔",
"parent": null,
"likes": []
},
This is just an small part of json.
and in main.dart
import 'dart:async';
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
Future<Album> fetchAlbum() async {
final response = await http
.get(Uri.parse('https://myapiaddress'));
if (response.statusCode == 200) {
// If the server did return a 200 OK response,
// then parse the JSON.
return Album.fromJson(jsonDecode(response.body));
} else {
// If the server did not return a 200 OK response,
// then throw an exception.
throw Exception('Failed to load album');
}
}
class Album {
final String content;
Album({
required this.content,
});
factory Album.fromJson(Map<String, dynamic> json) {
return Album(
content: json['content'],
);
}
}
void main() => runApp(const MyApp());
class MyApp extends StatefulWidget {
const MyApp({Key? key}) : super(key: key);
#override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
late Future<Album> futureAlbum;
#override
void initState() {
super.initState();
futureAlbum = fetchAlbum();
}
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Fetch Data Example',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: Scaffold(
appBar: AppBar(
title: const Text('Fetch Data Example'),
),
body: Center(
child: FutureBuilder<Album>(
future: futureAlbum,
builder: (context, snapshot) {
if (snapshot.hasData) {
return Text(snapshot.data!.content);
} else if (snapshot.hasError) {
return Text('${snapshot.error}');
}
// By default, show a loading spinner.
return const CircularProgressIndicator();
},
),
),
),
);
}
}
the error i'm currentle getting FlutterError: List<dynamic> is not a subtype of type Map<String, dynamic>
I get some infos about this error from the internet is that API returns JSON array not json object so that is List not Map, But i don't know how to implement it, As i'm a beginner in flutter.
how do i rectify it?
You can change the fetchAlbum method to return all albums from the API:
Future<List<Album>> fetchAlbum() async {
final response = await http
.get(Uri.parse('https://myapiaddress'));
if (response.statusCode == 200) {
// If the server did return a 200 OK response,
// then parse the JSON.
jsonDecode(response.body).map((albumJson) => Album.fromJson(albumJson)).toList();
} else {
// If the server did not return a 200 OK response,
// then throw an exception.
throw Exception('Failed to load album');
}
}
class Album {
final String content;
Album({
required this.content,
});
factory Album.fromJson(Map<String, dynamic> json) {
return Album(
content: json['content'],
);
}
}
Thank you the problem has been solved.
I'm trying to create what should be a very simple flutter app that will load all data from a POST with parameters and create a scrolling list with the details.
currently I'm not getting any errors, however the loading circle just spins for ever even though the JSON has been successfully returned, any help or ideas would be greatly appreciated.
Here's what I have so far:
import 'dart:async';
import 'dart:convert';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
Future<List<Post>> fetchPosts(http.Client client) async {
var url = "contacts.json";
var client = new http.Client();
var request = new http.Request('POST', Uri.parse(url));
var body = {'type': 'getContacts'};
request.bodyFields = body;
var data = http.post(url, body: {"type": "getContacts"})
.then((response) {
print(response.body);
return compute(parsePosts, response.body);
});
}
// A function that will convert a response body into a List<Photo>
List<Post> parsePosts(String responseBody) {
final parsed = json.decode(responseBody).cast<Map<String, dynamic>>();
return parsed.map<Post>((json) => Post.fromJson(json)).toList();
}
class Post {
final String First;
final String Last;
final String Email;
final String Phone;
final String Photo;
final String Full;
Post({this.Full, this.First, this.Last, this.Photo, this.Email, this.Phone});
factory Post.fromJson(Map<String, dynamic> json) {
return new Post(
Full: json['Full'] as String,
First: json['First'] as String,
Last: json['Last'] as String,
Photo: json['Photo'] as String,
Email: json['Email'] as String,
Phone: json['Phone'] as String,
);
}
}
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
final appTitle = 'CONTACTS';
return MaterialApp(
title: appTitle,
home: MyHomePage(title: appTitle),
);
}
}
class MyHomePage extends StatelessWidget {
final String title;
MyHomePage({Key key, this.title}) : super(key: key);
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(title),
),
body: FutureBuilder<List<Post>>(
future: fetchPosts(http.Client()),
builder: (context, snapshot) {
if (snapshot.hasError) print(snapshot.error);
return snapshot.hasData
? PhotosList(photos: snapshot.data)
: Center(child: CircularProgressIndicator());
},
),
);
}
}
class PhotosList extends StatelessWidget {
final List<Post> photos;
PhotosList({Key key, this.photos}) : super(key: key);
#override
Widget build(BuildContext context) {
return ListView.builder(
itemCount: photos == null ? 0 : photos.length,
itemBuilder: (BuildContext context, i) {
return new ListTile(
title: new Text(photos[i].Last + " " + photos[i].First),
subtitle: new Text(photos[i].Phone),
leading: new CircleAvatar(
backgroundImage:
new NetworkImage(photos[i].Photo),
)
);
}
);
}
}
Test JSON data as such:
[{
"Full": "Billy Bobbins",
"First": "Billy",
"Last": "Bobbins",
"Photo": "",
"Email": "billyb#here.com",
"Phone": "18885551212"
}, {
"Full": "Darron Dragonborn",
"First": "Darron",
"Last": "Dragonborn",
"Photo": "",
"Email": "dragond#here.com",
"Phone": "18005551111"
}]
Because you are using Future and async, you can use await for asynchronous operation.
So your fetchPosts should be like this
Future<List<Post>> fetchPosts(http.Client client) async {
var url = "contacts.json";
var client = new http.Client();
var request = new http.Request('POST', Uri.parse(url));
var body = {'type': 'getContacts'};
request.bodyFields = body;
var data = await http.post(url, body: {"type": "getContacts"});
print(data.body);
return await compute(parsePosts, data.body);
}
You can also refer to this.It is really helpful.
https://flutter.dev/docs/cookbook/networking/background-parsing