Unable to post MAP values to https post in flutter - json

I have made a separate class which is my model class and has a function that posts to DISCORD WEB HOOK. I am setting the map values to true from the FORM UI screen. The textformfield value gets POSTED while MAP gives an error as following, just the textfield value gets posted and works fine but MAP doesn't work. Am I writing bad JSON?
P.S it is a discord hook so "content" is neccessary
I/flutter (26346): {"content": ["Could not interpret \"['testing options', {'Spot': True, 'Red': True, 'Thich': False, 'Dry': True, 'Strech': False}]\" as string."]}
Here is the code for the class
import 'dart:convert';
import 'package:http/http.dart';
class DataPush {
static const String Spot = 'Spot';
static const String Red = 'Red';
static const String Thick = 'Thich';
static const String Dry = 'Dry';
static const String Strech = 'Strech';
String firstName = '';
Map<String, bool> passions = {
Spot: false,
Red: false,
Thick: false,
Dry: false,
Strech: false,
};
save() {
print("Saved");
}
makePostRequest() async {
final uri = Uri.parse(
'MY DISCORD WEBHOOK URL');
final header = {'Content-Type': 'application/json'};
Map<String, dynamic> body = {
"content": [firstName, passions]
};
String jsonBody = json.encode(body);
Response response = await post(
uri,
headers: header,
body: jsonBody,
);
int statusCode = response.statusCode;
String responseBody = response.body;
print(statusCode);
print(responseBody);
}
}

Remove this line and directly pass Map to post function.
String jsonBody = json.encode(body);

The Discord webhook documentation specifies the content field as a string, but you are sending an array as the value of that field - If you really want to send an array in the content field, you'll need to encode it as a json string itself first.
makePostRequest() async {
final uri = Uri.parse(
'MY DISCORD WEBHOOK URL');
final header = {'Content-Type': 'application/json'};
Map<String, dynamic> body = {
"content": json.encode([firstName, passions]) // Change this line
};
String jsonBody = json.encode(body);
Response response = await post(
uri,
headers: header,
body: jsonBody,
);
int statusCode = response.statusCode;
String responseBody = response.body;
print(statusCode);
print(responseBody);
}

Related

Flutter/Dart Error - NoSuchMethodError (NoSuchMethodError: Class 'String' has no instance method 'map'

I receive an error that has something to do with JSON receiver inside Flutter/Dart.
Had to share in a docs file since the full json response is pretty long. It had like 15 columns error log
Detail Class
class Detail {
String kodkursus;
String namakursus;
String kursusdescription;
Detail(
{required this.kodkursus,
required this.namakursus,
required this.kursusdescription});
factory Detail.fromJson(Map<String, dynamic> json) {
return Detail(
kodkursus: json['crs_code'] as String,
namakursus: json['crs_title_bm'] as String,
kursusdescription: json['crs_description_bm'] as String,
);
}
}
Code
Future<dynamic> generateDetailList() async {
var url = 'http://10.0.2.2:81/login_testing/kursus_display.php';
var data = {'usr_id': widget.username2};
var response = await http.post(url, body: json.encode(data));
var list = json.decode(json.encode(response.body));
List<Detail> _detail =
list.map<Detail>((json) => Detail.fromJson(json)).toList();
detailDataSource = DetailDataSource(_detail);
return _detail;
}
Return (full error log)
NoSuchMethodError (NoSuchMethodError: Class 'String' has no instance method 'map'...
I fairly new to this Flutter/Dart but I got the feeling it had something to do with the json, it just I cant get my head over it
Please check your API response because this error generates when there are difference in datatype.
this error says your app response it in String and you are accessing this as map so please check your API response or
try to replace this :
var list = json.decode(json.encode(response.body));
with :
var list = json.decode(response.body);
because json.encode method encodes all list data and that values datatype is String so it gives error.
Replace your function generateDetailList as such:
Future<List<Detail>?> generateDetailList() async {
Uri url = Uri.parse('http://10.0.2.2:81/login_testing/kursus_display.php');
Map<String, String> data = {'usr_id': 'widget.username2'};
http.Response response = await http.post(url, body: json.encode(data));
// var list = json.decode(json.encode(response.body));
var responseMap = await jsonDecode(response.body);
if (response.statusCode == 200) {
List<Detail> _details =
responseMap.map<Detail>((x) => Detail.fromJson(x)).toList();
return _details;
} else {
return null;
}
}
And try not to use var everywhere.

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: Send JSON body for Http GET request

I need to make a GET request to an API from my Flutter app which requires request body as JSON (raw).
I tested the API with JSON request body in Postman and it seems to be working fine.
Now on my Flutter application I am trying to do the same thing:
_fetchDoctorAvailability() async {
var params = {
"doctor_id": "DOC000506",
"date_range": "25/03/2019-25/03/2019" ,
"clinic_id":"LAD000404"
};
Uri uri = Uri.parse("http://theapiiamcalling:8000");
uri.replace(queryParameters: params);
var response = await http.get(uri, headers: {
"Authorization": Constants.APPOINTMENT_TEST_AUTHORIZATION_KEY,
HttpHeaders.contentTypeHeader: "application/json",
"callMethod" : "DOCTOR_AVAILABILITY"
});
print('---- status code: ${response.statusCode}');
var jsonData = json.decode(response.body);
print('---- slot: ${jsonData}');
}
However the API gives me an error saying
{message: Missing input json., status: false}
How do I send a raw (or rather JSON) request body for Http GET request in Flutter?
GET
GET requests are not intended for sending data to the server (but see this). That's why the http.dart get method doesn't have a body parameter. However, when you want to specify what you are getting from the server, sometimes you need to include query parameters, which is a form of data. The query parameters are key-value pairs, so you can include them as a map like this:
final queryParameters = {
'name': 'Bob',
'age': '87',
};
final uri = Uri.http('www.example.com', '/path', queryParameters);
final headers = {HttpHeaders.contentTypeHeader: 'application/json'};
final response = await http.get(uri, headers: headers);
POST
Unlike GET requests, POST requests are intended for sending data in the body. You can do it like this:
final body = {
'name': 'Bob',
'age': '87',
};
final jsonString = json.encode(body);
final uri = Uri.http('www.example.com', '/path');
final headers = {HttpHeaders.contentTypeHeader: 'application/json'};
final response = await http.post(uri, headers: headers, body: jsonString);
Note that the parameters were a Map on the Dart side. Then they were converted to a JSON string by the json.encode() function from the dart:convert library. That string is the POST body.
So if the server is asking you to pass it data in a GET request body, check again. While it is possible to design a server in this way, it isn't standard.
uri.replace... returns a new Uri, so you have to assign it into a new variable or use directly into the get function.
final newURI = uri.replace(queryParameters: params);
var response = await http.get(newURI, headers: {
"Authorization": Constants.APPOINTMENT_TEST_AUTHORIZATION_KEY,
HttpHeaders.contentTypeHeader: "application/json",
"callMethod" : "DOCTOR_AVAILABILITY"
});
using post:
var params = {
"doctor_id": "DOC000506",
"date_range": "25/03/2019-25/03/2019" ,
"clinic_id":"LAD000404"
};
var response = await http.post("http://theapiiamcalling:8000",
body: json.encode(params)
,headers: {
"Authorization": Constants.APPOINTMENT_TEST_AUTHORIZATION_KEY,
HttpHeaders.contentTypeHeader: "application/json",
"callMethod" : "DOCTOR_AVAILABILITY"
});
You can use Request class as following:
var request = http.Request(
'GET',
Uri.parse("http://theapiiamcalling:8000"),
)..headers.addAll({
"Authorization": Constants.APPOINTMENT_TEST_AUTHORIZATION_KEY,
HttpHeaders.contentTypeHeader: "application/json",
"callMethod": "DOCTOR_AVAILABILITY",
});
var params = {
"doctor_id": "DOC000506",
"date_range": "25/03/2019-25/03/2019",
"clinic_id": "LAD000404"
};
request.body = jsonEncode(params);
http.StreamedResponse response = await request.send();
print(response.statusCode);
print(await response.stream.bytesToString());
Also, note that Postman that can convert an API request into a code snippet in more than 15 languages. If you select Dart, you will find a similar code to above.
It may help someone those who used Getx for api integration . We can use request method for these kind of requirement.
Map<String, dynamic> requestBody = { 'id' : 1};
Response<Map<String, dynamic>> response =
await request(url, 'get', body: requestBody);
if you want to send complex/nested data through a GET request like the sample below, you can use a simple class i created on github
https://github.com/opatajoshua/SimplifiedUri
final params = {
'name': 'John',
'columns': ['firstName', 'lastName'],
'ageRange': {
'from': 12,
'to': 60,
},
'someInnerArray': [1,2,3,5]
};
final Uri uri = SimplifiedUri.uri('http://api.mysite.com/users', params);
final headers = {HttpHeaders.contentTypeHeader: 'application/json'};
final response = await http.get(uri, headers: headers);
output
http://api.mysite.com/users?name=John&columns%5B%5D=firstName&columns%5B%5D=lastName&ageRange%5Bfrom%5D=12&ageRange%5Bto%5D=60&someInnerArray%5B%5D=1&someInnerArray%5B%5D=2&someInnerArray%5B%5D=3&someInnerArray%5B%5D=5

How can I post a request using an already received authorization token?

So I have created a login screen that posts the user's information and then returns a token which is then store in their SharedPreferences. How can I now use this token to with another request to display the information that is associated with their profile.
I believe I have to create another post request. This time with slightly different headers and include the token in the header. Then parse the response into usable data?
Try this!
Map<String, dynamic> parameterData;
Map<String, dynamic> responseMap = new Map();
String url = Host.baseURL + "API_URL";
parameterData.putIfAbsent("user_name", () => "ABC");
String data = json.encode(parameterData);
try {
await http.post(Uri.encodeFull(url),
headers: {"Accept": "application/json", "auth": "put_acess_token_here"},
body: {"data": data}).catchError((onError) {
}).then((response) {
if (response != null) {
responseMap = json.decode(response.body);
}
});
} catch (exception, stackTrace) {
printLog(exception);
printLog(stackTrace);
}
You need to import below
import 'package:http/http.dart' as http;

Returning HttpResponseMessage from MVC HttpPost, with content of JSON

My first post on StackOverflow but I am a long time lurker! Hopefully I canget some help on an issue I'm working on.
I am trying to achieve the following. The code below is setting the content to be a JSON string which contains the following...
{
"access_token": "value1",
"expires_in": "value2",
"client_in": null,
"scope": "value3"
}
and here is the code which sends the HttpResponseMessage back to the client.
[HttpPost]
public HttpResponseMessage token(string grant_type,
string code,
string client_id,
string client_secret,
string redirect_uri)
{
WpOAuth2TokenRetValSuccessVM OA2_Success = new WpOAuth2TokenRetValSuccessVM();
OA2_Success.access_token = "value1";
OA2_Success.client_in = client_id;
OA2_Success.expires_in = "value2"; //...The number of seconds left in the lifetime of the token
OA2_Success.scope = "value3"; //...Each access token can have only 1 scope
HttpResponseMessage response = new HttpResponseMessage();
response.StatusCode = HttpStatusCode.OK;
string strJson = JsonConvert.SerializeObject(OA2_Success, Newtonsoft.Json.Formatting.Indented);
StringContent n = new StringContent(strJson, Encoding.UTF8, "application/json");
response.Content = n;
return response;
}
Now then, on the client side for the life of me I cannot get the JSON string back out of the content. Here is the code that I am using to read the content.
HttpClient httpClient = new HttpClient();
httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
var postData = new List<KeyValuePair<string, string>>();
postData.Add(new KeyValuePair<string, string>(str_KEY1, str_VALUE1));
postData.Add(new KeyValuePair<string, string>(str_KEY2, str_VALUE2));
postData.Add(new KeyValuePair<string, string>(str_KEY3, str_VALUE3));
postData.Add(new KeyValuePair<string, string>(str_KEY4, str_VALUE4));
postData.Add(new KeyValuePair<string, string>(str_KEY5, str_VALUE5));
HttpContent content = new FormUrlEncodedContent(postData);
httpClient.PostAsync(strURI, content).ContinueWith(requestTask =>
{
// Get HTTP response from completed task.
HttpResponseMessage response = requestTask.Result;
// Check that response was successful or throw exception
response.EnsureSuccessStatusCode();
// Read response asynchronously as string and write out
var responseValue = response.Content.ReadAsStringAsync();
responseValue.Wait();
string n = responseValue.Result;
var i = 0;
});
Now then, string n's content is as follows, but how do I get at the JSON???
Thanks all.
StatusCode: 200, ReasonPhrase: 'OK', Version: 1.1, Content: System.Net.Http.StringContent, Headers:
{
Content-Type: application/json; charset=utf-8
}
Sounds like you figured out the problem, but it should be noted that since you're using Web API, there's no need to serialize the data and build the HttpResponseMessage yourself; let the framework do it for you:
[HttpPost]
public WpOAuth2TokenRetValSuccessVM token(string grant_type,
string code,
string client_id,
string client_secret,
string redirect_uri)
{
return new WpOAuth2TokenRetValSuccessVM
{
access_token = "value1",
client_in = client_id,
expires_in = "value2",
scope = "value3"
};
}