I'm calling requesting server for data and getting following response.
{
"success": 1,
"data": [
{
"id": 1,
"name": "Kurti"
},
{
"id": 2,
"name": "Top"
}
],
"message": "Data fetched"
}
Modal class to convert json data coming from server.
class Product {
String categoryName;
int productId;
Product.fromJson(Map<String, dynamic> json) {
categoryName = json["id"];
productId = json["name"];
}
}
So from the server the format will be fix for every call like below...
{
"success": <Int>,
"message": <String>,
"data": <An array of Model class>
}
For that I've created below class...
class ServerResponse<T> {
String message;
int success;
List<T> data;
ServerResponse.fromJson(Map<String, dynamic> json) {
message = json["message"];
success = json["success"];
data = json["product_data"];
}
}
And this is how I'm calling api...
class ServerManager {
final baseUrl = isProduction ? liveServer : stagingServer;
var headers = {"consumer-key": "sdfgdqwrtw34563t545"};
dynamic callWSToGetData({Map<String, String> params}) async {
var client = http.Client();
var url = baseUrl + allProducts;
print("URL = $url");
print("params: $params");
print("header: $headers");
var response = await client.post(url, headers: headers, body: params);
var json = converter.jsonDecode(response.body);
return json;
}
}
Calling api to get data as following.
Map<String, String> params = {"categories_id": "1", "language_id": "1", "type": "Newest", "customers_id": "0", "page_number": "0"};
var response = ServerManager().callWSToGetData(params: params);
var res = ServerResponse<Product>.fromJson(response);
print(res.data);
So when I ran this code I'm getting following error.
type 'Future' is not a subtype of type 'Map'
The question is...
How can I create a single generic class that can be used to handle server responses?
Any help please.
type 'Future' is not a subtype of type 'Map'
This is probably due to missing await call. Your callWSToGetData has async in declaration so it's type will be Future.
To use generics you need to pass the type. So your code will look like this:
var response = await ServerManager().callWSToGetData(); //how can I use generic here
var res = ServerResponse<Product>.fromJson(response);
print(res.data);
Related
Im retrieving data in database using ajax but when I'm calling the method in controller I getting an error in JsonConvert.SerializeObject(model, Formatting.Indented, new JsonSerializerSettings and I don't know why. Here's my code:
Views
function EditRecord(Id) {
var url = "/Admin/GetCategoryGroupById?Id=" + Id;
$("#ModalTitle").html("Update Category Group");
$("#MyModal").modal();
$.ajax({
type: "GET",
url: url,
success: function (data) {
var obj = JSON.parse(data);
$("#Id").val(obj.Id);
$("#Name").val(obj.Name);
//$("#Status option:selected").text(obj.tblDepartment.DepartmentName);
$("#cbStatus").val(obj.Status);
}, error: function (xhr, status, error) {
alert(error);
}
})
}
Controllers
public JsonResult GetCategoryGroupById(int Id)
{
CategoryGroup model = db.CategoryGroups.Where(x => x.Id == Id).SingleOrDefault();
string value = string.Empty;
value = JsonConvert.SerializeObject(model, Formatting.Indented, new JsonSerializerSettings
{
ReferenceLoopHandling = ReferenceLoopHandling.Ignore
});
return Json(value, JsonRequestBehavior.AllowGet);
}
The error:
Please help me. Thank you.
i think that your db doesn't have any CategoryGroups with the specified id. this is why the singleOrDefault returns null. so you need to add an if statement to check weather model is null
I am trying to post a request to api with an object as"
var params = {
"item": "itemx",
"options": [1,2,3],
};
print(params);
try {
Response response = await _dio.post(getAddToCartURL,
queryParameters: params,
options: Options(headers: {
HttpHeaders.contentTypeHeader: "application/json",
}));
} catch (error, stackTrace) {
print("Exception occurred: $error stackTrace: $stackTrace");
return false;
}
Dio sends the object as :
POST /api/add-to-cart/?item=itemx&options%5B%5D=1&options%5B%5D=2&options%5B%5D=3
in which the api recognize it as a bad request.
what is wrong that i am doing here? I have even tried the list as [ "1","2","3"], it is the same.
It all depends on how the API expects it. I would suggest trying to encode it as JSON.
var params = {
"item": "itemx",
"options": jsonEncode([1,2,3]),
};
But sending complex data in query parameters isn't always that easy. Since you are using POST anyway, maybe send a JSON object as body instead of using query parameters.
var params = {
"item": "itemx",
"options": [1,2,3],
};
...
Response response = await _dio.post(getAddToCartURL,
options: Options(headers: {
HttpHeaders.contentTypeHeader: "application/json",
}),
data: jsonEncode(params),
);
another example for any one might be helpful , posting fomr data
var formData = FormData.fromMap({
'data': json.encode(
{'salt': salt, 'placeholder': 'palceholder',
'method_name': 'app_details'})
});
var response = await dio.post(
BaseUrl,
data: formData,
);
the final result of your request is this
I am trying to make a POST request to a Firebase Notifications API using Vapor 1.5 and Firebase Legacy Protocol, but I get failure response.
response is JSON(node: Node.Node.object(["multicast_id":
Node.Node.number(5936281277445399934), "failure": Node.Node.number(0),
"canonical_ids": Node.Node.number(0), "results":
Node.Node.array([Node.Node.object(["message_id":
Node.Node.string("0:1527074314969790%c7ade8b9f9fd7ecd")])]),
"success": Node.Node.number(1)]))
EDIT
Making the request through POSTMan fails with error "The request was missing an Authentication Key (FCM Token)."
class FirebaseRequester {
let fcmLegacyServerKey = "AIzaSyDSuXXXXXXkCafTQay5_r8j3snvVos"
func sendNotification(payLoad: JSON) throws -> Response {
var response: Response?
do {
let responseFCM = try drop.client.post("https://fcm.googleapis.com/fcm/send",
headers: ["Content-Type":"application/json","Authorization": "key\(fcmLegacyServerKey)"],
query: [:],
body: payLoad.makeBody())
response = responseFCM
}catch let error {
let message = error.localizedDescription
logErr.prints(message: message)
throw Abort.custom(status: .badRequest, message: message)
}
guard let rsp = response?.json else {
let message = "no json received on line \(#line)"
drop.log.error(message)
logErr.prints(message: message)
throw Abort.custom(status: .badRequest, message: message)
}
print("rsp in json format is \(rsp)")
return response!
}//end of sendNotification()
}//end of class FirebaseRequester
//make another class here and initialize it with FirebaseRequester
//get data from Client App
// validate data
// finally, create the payLoad and call sendNotification(:)
//request should look like
{
"aps": {
"alert": "Breaking News!",
"sound": "default",
"link_url": "https://raywenderlich.com"
}
}
let fcmKeyToSendTo = "someDeviceTokenKeyReceivedFromClient_biHZNI-e9E53WEkCzrki"
let data = try Node(node: ["alert": "alert", "sound": "sound", "link_url": "https://www.someWebsite.com"])
var payLoadObj = try JSON(node: ["aps" : data])
payLoadObj["to"] = try JSON(node: fcmKeyToSendTo)
do {
let _ = try firebaseRequester.sendNotification(payLoad: payLoadObj)
}catch{
logErr.prints(message: error.localizedDescription)
}
let message = "notification Sent"
return try JSON(node:["success":message])
In sendNotification(payload:) I had a typo, I missed = after key. It should have been "key=\(fcmLegacyServerKey)"
In sendNotification(payload:), payLoad.makeBody should not be called, I should have just passed the JSON object payLoad as an argument to the .post request.
The JSON object of the notification was clearly badly formatted from the outset. The message type I wanted to send was notification, but I was passing in a key named aps. I should have passed key notification as shown below.
.
class FirebaseRequester {
let fcmLegacyServerKey = "AIzaSy....vVos"
func sendNotification(payLoad: JSON) throws -> Response {
var response: Response?
do {
let responseFCM = try drop.client.post("https://fcm.googleapis.com/fcm/send",
headers: ["Content-Type":"application/json","Authorization": "key=\(fcmLegacyServerKey)"],
query: [:],
body: payLoad
response = responseFCM
}catch let error {
let message = error.localizedDescription
logErr.prints(message: message)
throw Abort.custom(status: .badRequest, message: message)
}
guard let rsp = response?.json else {
let message = "no json received on line \(#line)"
drop.log.error(message)
logErr.prints(message: message)
throw Abort.custom(status: .badRequest, message: message)
}
return response!
}//end of sendNotification()
}//end of class FirebaseRequester
class TestRouteNow {
let firebaseRequester: FirebaseRequester
init(firebaseRequester: FirebaseRequester) {
self.firebaseRequester = firebaseRequester
}
func addRoutes(drop: Droplet) {
drop.post("test", "notif", handler: postNotification)
}
func postNotification(request: Request) throws -> ResponseRepresentable {
let fcmDevice = "someDeviceTokenReceivedFromClientApp"
let data = try Node(node: ["title": "title","body": "body", "sound": "default", "badge":"60"])
var payLoadObj = try JSON(node: ["notification": data])
payLoadObj["to"] = try JSON(node: fcmDevice)
do {
let _ = try firebaseRequester.sendNotification(payLoad: payLoadObj)
}catch{
logErr.prints(message: error.localizedDescription)
}
let message = "notification Sent"
return try JSON(node:["success":message])
}
}//end of class
// request body
{
"to" : "cQDtm_someDeviceTokenReceivedFromClient",
"priority":"high",
"notification": {
"title":"Booking Rescheduled",
"body": "Cancelled Booking 7830593, for Mon, 12 March",
"sound":"default",
"badge": "100"
}
}
I'm using grpcc, which is based on protobuf.js, to test my grpc service APIs.
My .proto file:
message MyRequest {
string userId = 1;
map<string, string> params = 2;
}
I tried the following json body to send a request:
{userId : "my_user_id" , params: { name: "my_name"}}
{userId : "my_user_id" , params: [{"name":"my_name"}] }
But this gives the following error:
Error: Illegal value for Message.Field....MyRequest.params of type string: object (expected ProtoBuf.Map or raw object for map field)
How to correctly represent a protobuf map as a json?
The proper json body would be the following:
{ "userId": "my_user_id", "params": { "name": "my_name" } }
What you've tried doing is an array of maps, which doesn't really mean anything in the context of protobuf. A map<string, string> is exactly the description of a json object, so more than one value would be represented the following way:
{ "params": { "key1": "value1", "key2": "value2" } }
No need for an array.
I have an angular application, and I am trying to get a list of users from the server. I ran into an issue. I have page call CurrentUsers. If CurrentUsers method returns a Json Object, the entire object is display on the page regardless of what I do in the app controller and html page. If the method return a view, it does not display anything. However, I can hard code the json object in the cotroller, and it will work fine.
As a result, I created another method to return the json object. I made a call to that method, but it never reached the server. Your help will be very much appreciated.
The CurrentUsers Method returning a JSON Object, the entire json object display on the screen regardless
[HttpGet]
public JsonResult CurrentUsers()
{
List<Users> currentUser = new List<Users>()
{
new Users{ UserName = "JDoe", Professor="SSmith", Course = "English1"},
new Users{ UserName = "ADan", Professor="SDhor", Course = "Science"},
new Users{ UserName = "ADes", Professor="SCarry", Course = "Religion101"},
new Users{ UserName = "DJay", Professor="SCrowe", Course = "Teaching101"},
new Users{ UserName = "MAnne", Professor="TRow", Course = "PreCalc"},
};
return Json(new { Ok = true, data= currentUser });
// return View();
}
If the above method return a View, I can modify the controller as
shown below, and I will see the appropriate Information
Registration.controller('CurrentUsersController', function ($scope, $http) {
$scope.currentUsers = [{ "Professor": "SSmith", "UserName": "JDoe", "Course": "English1" }, { "Professor": "SDhor", "UserName": "ADan", "Course": "Science" }, { "Professor": "SCarry", "UserName": "ADes", "Course": "Religion101" }]
});
I modified the controller to use a service and created the method below to read the Current Users so that the view can simply return a View(). However, I have not been able to get the 'GET'to work.
[HttpGet]
public JsonResult GetUsers()
{
List<Users> currentUser = new List<Users>()
{
new Users{ UserName = "JDoe", Professor="SSmith", Course = "English1"},
new Users{ UserName = "ADan", Professor="SDhor", Course = "Science"},
new Users{ UserName = "ADes", Professor="SCarry", Course = "Religion101"},
new Users{ UserName = "DJay", Professor="SCrowe", Course = "Teaching101"},
new Users{ UserName = "MAnne", Professor="TRow", Course = "PreCalc"},
};
return Json(new { Ok = true, data = currentUser , message =
"Success"}, JsonRequestBehavior.AllowGet);
}
the modify CurrentUsers Method to return a view
public ActionResult CurrentUsers()
{
return View();
}
My modify controller
Registration.controller('CurrentUsersController', function ($scope, GetUSerService) {
$scope.message = 'this is the Current User controller';
$scope.currentUsers = [];
var result = GetUSerService.getData()
.then(function (result) {
console.log('the result');
console.log(result.data);
});
});
my service
Registration.service('GetUSerService', function ($http,$q) {
this.getData = function () {
var deferredObject = $q.defer();
$http.get('/Home/GetUsers').
success(function (data) {
console.log('service call data');
console.log(data);
deferredObject.resolve({ success: true, data : data.data });
}).
error(function () {
deferredObject.resolve({ success: false, data : '' });
});
return deferredObject.promise;
};
});
Updated 10/6 #5:50
#FernandoPinheiro answer works for me. The only thing is that the GetUsers action is being called twice.
Updated 10/7
I figured out why the post was being done twice. On my template, I had ng-app="Registration", and I had ng-controller= "CurrentUsersController". Because I specified the controller name in the route provider, I did not need it to add it to the partial view. As soon as I removed it from the view, it worked as expected.
Your GetUserService is calling $http.post('/Home/GetUsers') instead of $http.get('/Home/GetUsers').
Besides, shouldnt you set the Route attribute for the action ?