How to make an API request in Flutter - json

I'm new to Flutter, so I'm not sure how I am supposed to make an API call, coming from Java where I was using Retrofit.
JSON Response:
{
"total": 13,
"rows": [
{
"id": 1,
"name": "Name"
}
]
}
Model class:
class Category {
int total;
List<Rows> rows;
Category({this.total, this.rows});
Category.fromJson(Map<String, dynamic> json) {
total = json['total'];
if (json['rows'] != null) {
rows = new List<Rows>();
json['rows'].forEach((v) {
rows.add(new Rows.fromJson(v));
});
}
}
}
class Rows {
String name;
Rows({this.name});
Rows.fromJson(Map<String, dynamic> json) {
name = json['name'];
}
}
Main class
List<Rows> rows = [];
Future<List<Rows>> getData() async {
var response = await http.get(
Uri.encodeFull("http://192.168.0.10/api/v1/categories"),
headers: {
"Authorization": "API",
"Accept": "application/json"
}
);
var jsonData = json.decode(response.body);
}
I'm not sure how to approach I tried getting the object with Rows.fromJson(), but I only get 'Instance of Rows' and by calling name I get null.

The approach is correct but for list you should use list.map for deserializing lists.
Try this, I didn't tested it, I just wrote it looking at your examples
var response = await http.get(
Uri.encodeFull("http://192.168.0.10/api/v1/categories"),
headers: {
"Authorization": "API",
"Accept": "application/json"
}
);
List<Rows> rows = [];
Map map = json.decode(response.body);
List l = map["rows"];
rows = l.map((map) => Rows.fromJson(map)).toList();

You can use json_serializable and json_annotation and build_runner

Related

No Data in Google Data Studio

I'm trying to show JSON data got from API in Google Data Studio.
so I created community connector and in script verified JSON data from api.
here is script code.
function getFields(request) {
var cc = DataStudioApp.createCommunityConnector();
var fields = cc.getFields();
var types = cc.FieldType;
// var aggregations = cc.AggregationType;
fields.newDimension()
.setId('username')
.setType(types.TEXT);
fields.newMetric()
.setId('version')
.setType(types.NUMBER);
fields.newDimension()
.setId('address')
.setType(types.TEXT);
return fields;
}
function getSchema(request) {
var fields = getFields(request).build();
return { schema: fields };
}
function responseToRows(requestedFields, response) {
// Transform parsed data and filter for requested fields
var row = [];
requestedFields.asArray().forEach(function (field) {
switch (field.getId()) {
case 'username':
return row.push(response.result.user.createdByName);
case 'version':
return row.push(response.result.user.version);
case 'address':
return row.push(response.result.user.address);
default:
return row.push('');
}
});
return { values: row };
}
function getData(request) {
var requestedFieldIds = request.fields.map(function(field) {
return field.name;
});
var requestedFields = getFields().forIds(requestedFieldIds);
// Fetch and parse data from API
var options = {
'method' : 'post',
'contentType': 'application/json',
"headers":{ "api-key": request.configParams.api_key },
"payload": "{username:\""+username+"\", password: \""+password+"\"}",
'muteHttpExceptions': true
};
var response = UrlFetchApp.fetch(url, options);
var parsedResponse = JSON.parse(response);
var rows = responseToRows(requestedFields, parsedResponse);
console.log('getData request', parsedResponse);
return {
schema: requestedFields.build(),
rows: rows
};
}
this is JSON file
{
"result": {
"user": {
"type": "User",
"id": 1073787385,
"address": null,
"version": 1675247127459332096,
"createdBy": 310055,
"createdByName": "Jeirick Hiponia",
}
}
}
Result in data studio.
why don't address show?
And why no data? I think row.push in responseToRows() function is issue.
I'd like to show data like this.

Store a api response data in firebase collections using flutter

So, I have been making a post request to a REST API and I want to store the response data in the firebase cloud store collection.
What I have done so far:
I have created the model class for the response data and have written a function that will make this post-call.
I am not getting any such error but still, neither the response is getting printed in the console nor the data is being uploaded in the firebase.
Also, I have checked with almost all the StackOverflow questions that relate to my kind of problem.
Herewith I am attaching my code snippets:
Function:
//This function is only not getting called I don't know why.
final List<KycDetails> _kyc = [];
Dio dio = Dio();
TextEditingController aadhar = TextEditingController();
Future<List<KycDetails>> postData() async {
const String pathUrl = 'https://jsonplaceholder.typicode.com/posts';
dynamic data = {'title': aadhar.text, 'body': 'Flutter', 'userId': 1};
List<KycDetails> details = [];
var response = await dio.post(pathUrl,
data: data,
options: Options(
headers: {'Content-Type': 'application/json; charset=UTF-8'}));
if (response.statusCode == 200) {
print('ok');
var urjson = jsonDecode(response.data);
for (var jsondata in urjson) {
details.add(KycDetails.fromJson(jsondata));
}
}
return details;
}
Widget where I am calling the function and storing the data in firebase
InkWell(
hoverColor: Colors.red,
onTap: () async {
print('API CALLING');
await postData().then((value) {
setState(() {
_kyc.addAll(value);
});
print(value);
});
Map<String, String> data = {
"aadhar": aadhar.text,
"title": _kyc[0].title,
"userId": _kyc[0].userId.toString(),
};
FirebaseFirestore.instance.collection('kyc').add(data);
},
child: const Text('Submit'),
),
API response data:
{"title": "resume", "body": "Flutter", "userId": 1, "id": 101}
Model Class:
class KycDetails {
KycDetails({
required this.title,
required this.body,
required this.userId,
required this.id,
});
String title;
String body;
int userId;
int id;
factory KycDetails.fromJson(Map<String, dynamic> json) => KycDetails(
title: json["title"],
body: json["body"],
userId: json["userId"],
id: json["id"],
);
Map<String, dynamic> toJson() => {
"title": title,
"body": body,
"userId": userId,
"id": id,
};
}
I hope I have provided you with the necessary information
Am stuck on this problem for quite a few days Would appreciate it if anyone can solve my problem considering my code.
For starters, when you make a post request the success code you're looking for is 201 indicating that a resource has been successfully created.
So nothing in this code block will run.
if (response.statusCode == 200) {
print('ok');
var urjson = jsonDecode(response.data);
for (var jsondata in urjson) {
details.add(KycDetails.fromJson(jsondata));
}
}
response.data doesn't need jsonDecode here. It returns in the form of a map so you can cast it as such.
So this
var urjson = jsonDecode(response.data);
can be this
final urjson = response.data as Map<String, dynamic>;
As for this line
for (var jsondata in urjson) {
details.add(KycDetails.fromJson(jsondata));
}
The response is a single map, not a list. That single map is in the form of your KycDetails model so you don't need to loop through anything.
So you can create your object with your fromJson method.
final kycDetail = KycDetails.fromJson(urjson);
Then you can just do this to add a properly initiated KycDetails object to the list.
details.add(kycDetail);
If all you're trying to do is add a single object to Firebase then none of this in your onTap is necessary. Also trying to access the property at index 0 will not be the most recent addition to the list. You'd need to add the index of the last item in the list.
Map<String, String> data = {
"aadhar": aadhar.text,
"title": _kyc[0].title,
"userId": _kyc[0].userId.toString(),
};
FirebaseFirestore.instance.collection('kyc').add(data);
You can just add to Firebase from your postData function.
if (response.statusCode == 201) {
print('ok');
final urjson = response.data as Map<String, dynamic>;
final kycDetail = KycDetails.fromJson(urjson);
details.add(kycDetail);
FirebaseFirestore.instance.collection('kyc').add(kycDetail.toJson());
}

Flutter json.decode() sometimes works and sometimes doesnt while parsing the same object

I'm new to flutter and was working with json. when I am decoding the response I got from the server by using json.decode() I sometimes get the following error
flutter: FormatException: Unexpected character (at character 21)
sometimes it works perfectly.
this is my code
try {
Map<String, dynamic> map = new Map<String, dynamic>.from(
json.decode(contents));
if (map["CompletedJobPackages"] != null) {
DataStream.compleatedJobspackage =
DataStream.parseCompletedJobs(map["CompletedJobPackages"]);
print(map["CompletedJobPackages"]);
compleatedJobs = DataStream.compleatedJobspackage;
}
CompletedJobloaded = true;
}
catch(e){
print(e);
ToastUtils.showCustomToast(context, "An Error Occured. Try Again !", false);
}
this is the object I'm trying to decode
{
"CompletedJob": {
"CompletedJobID": 7,
"DriverID": 34,
"JobNumber": "80252C20",
"TraderID": 7,
"TripType": "Two Way",
"CargoType": "wd",
"CargoWeight": 230,
"LoadingPlace": "dc",
"UnloadingPlace": "sd",
"LoadingDate": "2020-05-25",
"LoadingTime": "12:59:00",
"EntryExit": 1,
"AcceptedDelay": 4,
"Price": 34,
"Created": "2020-05-23T04:22:10.000Z"
},
"BillPaid": 0,
"DriverReview": {
"DriverReviewID": 11,
"DriverID": 34,
"TraderID": 7,
"CompletedJobID": 7,
"Rating": 100,
"Review": "dscsdc",
"Created": "2020-05-28"
}
},
Okay so after doing a little research I realized the problem.
the HTTP library I was using dart:io was not returning the complete JSON string in the response thus their was a problem in converting it into a JSON object
I just used
import 'package:http/http.dart' as http;
Map<String, String> requestHeaders = {
'Content-type': 'application/json',
'Accept': 'application/json',
'Authorization':"JWT "+DataStream.token
};
final response = await http.get(URLs.getCompletedJobPackagesURL(), headers:requestHeaders);
if (response.statusCode == 200) {
var jsonResponse = convert.jsonDecode(response.body);
print(jsonResponse);
Map<String, dynamic> map = convert.jsonDecode(response.body);
if(map["CompletedJobPackages"]!= null) {
DataStream.compleatedJobspackage =
DataStream.parseCompletedJobs(map["CompletedJobPackages"]);
compleatedJobs = DataStream.compleatedJobspackage;
}
setState(() {
});
}
instead of
import 'dart:io';
final client = HttpClient();
try{
final request = await client.getUrl(Uri.parse(URLs.getDrivingLicenceURL()));
request.headers.set(HttpHeaders.contentTypeHeader, "application/json; charset=UTF-8");
request.headers.add("Authorization", "JWT "+DataStream.token);
final response = await request.close();
response.transform(utf8.decoder).listen((contents) async {
// print(response.statusCode);
Map<String, dynamic> driverMap = jsonDecode(contents) as Map<String, dynamic>;
isloadlicence = true;
if(driverMap["CompletedJobPackages"]!= null) {
DataStream.compleatedJobspackage =
new DrivingLicence.fromJson(driverMap["CompletedJobPackages"]);
}
setState(() {
});
});
}catch(e){
print(e);
ToastUtils.showCustomToast(context, "An Error Occurred. Try Again !", false);
//pr.hide();
}
Definitely the problem is the emulator, after several days looking for the problem I found this post and I have verified that it does not fail on my real phone.
Different emulators fails different number of times (maybe something related to the ram??).
Also consider using compute(jsonDecode, response.body) to decode the string as indicated in Parse JSON in the background.
compute fails less times on emulators, but still failing sometimes. Doesn't fails in real phone.

how to post json array on flutter

I have some problem to post json array with flutter.
When I hit api with postman using json it works. Screenshot postman:
Since I know on body just accept Map <String,String> CMIIW
so i turn body into like this
List<Map<String,String>> products = [
{
"product_id": "1",
"buy_quantity": "1",
"product_price": "1000",
"is_voucher": "0",
},
{
"product_id": "2",
"buy_quantity": "2",
"product_price": "2000",
"is_voucher": "0",
},
];
final String jsonProduct = json.encode(products);// here im trying to
Map<String,String> _body = {
"buyer_id": '',
"buyer_firstname": postCart.buyerFirstname,
"phone_number": postCart.phoneNumber,
"transaction_total_price": postCart.transactionTotalPrice.toString(),
"voucher_id": 0.toString(),
"voucher_code": 0.toString(),
"payment_id": postCart.paymentId.toString(),
"payment_name": postCart.paymentName,
"products" : jsonProduct
};
but i still got error,
thanks!
I'm assuming that you are using the http package.
This is an example of how to make an HTTP POST request with a json payload on the body:
Future<Lead> createLead(String clientName, String clientEmail, String clientPhone, String eventId) async {
// Create storage
final storage = new FlutterSecureStorage();
// Get API url from env
String url = (DotEnv().env['BASE_URL'] + "/leads/create");
String authToken = await storage.read(key: 'api-token');
// Create some request headers
Map<String, String> requestHeaders = {
'Content-type': 'application/json',
'Accept': 'application/json',
'X-Token': authToken
};
final response = await http.post(
url,
// enconde some JSON data on the request body
body: json.encode(
{
'event_id': eventId,
'name': clientName,
'phone': clientPhone,
'email': clientEmail
}
),
headers: requestHeaders
);
if (response.statusCode == 200) {
final leadsJson = json.decode(response.body);
Lead lead = Lead.fromJson(leadsJson);
return lead;
} else {
// If that response was not OK, throw an error.
// throw Exception('Failed to load post');
return null;
}
}
Hope it helps.
If you want to achieve the JSON in the screen shot you need to make several changes.
Notice that the list of products shows unquoted integers when converted to JSON, so these need to be kept as ints in your Dart class. (Note the preferred syntax, too.)
var products = <Map<String, int>>[
{
'product_id': 1,
'buy_quantity': 1,
'product_price': 1000,
'is_voucher': 0,
},
{
'product_id': 2,
'buy_quantity': 2,
'product_price': 2000,
'is_voucher': 0,
},
];
The type of _body needs to change because it now contains a list as well as strings. (Keep the rest the same - like the toStrings - as your screenshot shows that even the integers are quoted as strings.)
var _body = <String, dynamic>{
'buyer_id': '',
'buyer_firstname': postCart.buyerFirstname,
'phone_number': postCart.phoneNumber,
'transaction_total_price': postCart.transactionTotalPrice.toString(),
'voucher_id': 0.toString(),
'voucher_code': 0.toString(),
'payment_id': postCart.paymentId.toString(),
'payment_name': postCart.paymentName,
'products': products
};
Lastly json and (preferably) utf8 encode the resulting map, and pass that as the body parameter of your http.post.
var bytes = utf8.encode(json.encode(_body));
await http.post(url, body: bytes, headers: someHeaders);
One of your headers could be content-type: application/json;encoding=utf-8 to tell the server that you are sending UTF8 encoded JSON.

Can I return raw json response in angular2

Is it possible for angular2 to return raw json response? Ex.
Component
getrawJson(){
this.someservice.searchJson()
.subscribe( somelist => this.somelist = somelist,
error => this.errorMsg = <any>error);
}
For service
searchJson(num: number, somestring: string, somestring2: string): Observable<stringDataObj> {
let body = JSON.stringify({"someJsonData"[{num, somestring, somestring2}]});
let headers = new Headers({ 'Content-Type': 'application/json' });
let options = new RequestOptions({ headers: headers });
return this.http.post(URL, body, options)
.map(this.jsonObj)
.catch(this.handleError);
}
private jsonObj(res: Response) {
let body;
return body{ };
}
The above implementation returns Array . Will there be a way for me to get the raw json data returned by the service? I'm expecting to have json response like below
{
"dataParam": [ {
"num": "08",
"somestring": "2016-10-03",
"somestring2": "2016-10-03"
}],
"someDatalist": [ {
"one": "08",
"two": 1,
"three": "2016-10-03"
}]
}
Thanks!
Yes off course you can !!
Actually angualar2 returns Response in the form of Observable instead of promise Like in angular1.x , so in order to convert that observable into raw Json format we have to use the default method of angular2 i.e
res.json()
There are no of method apart from .json() provided by angular which can be described here for more info.
methods include
res.text()
res.status
res.statusText
etc
https://angular.io/docs/ts/latest/api/http/index/Response-class.html
update
use your code like this
return this.http.post(URL, body, options)
.map(res => {return res.json()})
.catch(this.handleError);
}
private jsonObj(res: Response) {
return res.json() || {} ;
}