I could use some help. When making a GET request in Dart, I get an empty array. However, I can get a response in Postman. I'm rather stumped as to where the discrepancy is. I'm very new to Dart. I've tried more closely following the Postman code and didn't have any luck with that either.
My Dart code:
void loadData() async {
showLoading(context);
try {
hideDialog(context);
// String url = 'http://127.0.0.1:5000';
String url = '127.0.0.1:5000';
String endpoint = '/carrier_loadboard';
String option = 'Market';
String orgId = '2';
final queryParameters = {
'option': option,
'org_id': orgId,
};
final headers = {
'Authorization': 'Bearer$userToken',
'Content-Type': 'application/json',
'Cookie': 'session=$sessionCookie',
};
var creds = json.encode({
'email': 'carrier#domain.com',
'password': 'thePassword',
});
final uri = Uri.http(url, endpoint, queryParameters);
final response = await get(uri, headers: headers);
// var request = Request(
// 'GET',
// Uri.parse(
// 'http://127.0.0.1:5000/carrier_loadboard?option=Market&org_id=2'));
// request.body = creds;
// request.headers.addAll(headers);
// StreamedResponse response = await request.send();
if (response.statusCode == 200) {
// print(await response.stream.bytesToString());
print('Load data success');
List data = json.decode(response.body);
print(data);
if (data.isEmpty) {
print('No data');
}
} else {
print(response.reasonPhrase);
print('Load data failed');
}
} catch (e) {
devlog.log(e.toString());
}
}
And here is the code that Postman generates (which returns an array of data in Postman).
var headers = {
'Authorization': 'Bearer tokenTokenToken',
'Content-Type': 'application/json',
'Cookie': 'session=.cookieCodeCookieCode'
};
var request = http.Request('GET', Uri.parse('http://127.0.0.1:5000/carrier_loadboard?option='Market'&org_id='2''));
request.body = '''// {"email": "carrier#domain.com", "password":"thePassword"}\n''';
request.headers.addAll(headers);
http.StreamedResponse response = await request.send();
if (response.statusCode == 200) {
print(await response.stream.bytesToString());
}
else {
print(response.reasonPhrase);
}
This is the response in Dart:
[]
This is the first object in the Postman response:
[
{
"agent_id": null,
"assigned_carrier_id": null,
"carrier_org_id": 2,
"commodity": null,
"deliver_address": "700 4th St, San Francisco, CA 94107, USA",
"deliver_appt": null,
"deliver_appt_required": false,
"deliver_date": "2021-10-22T17:46:00",
"deliver_from_date": "2022-03-12T00:00:00",
"deliver_to_date": null,
"driver_id": null,
"expected_delivery_bid": "1000",
"expected_posting_bid": "1300",
"id": 104,
"load_num_broker": null,
"load_num_carrier": null,
"load_num_shipper": null,
"margin": null,
"notes": null,
"office_hr_end": null,
"office_hr_start": null,
"org_created": null,
"org_id_posted": 1,
"org_id_reposted": 1,
"org_name": null,
"pickup_address": "801 Alaskan Way, Seattle, WA 98104, USA",
"pickup_appt": null,
"pickup_appt_required": false,
"pickup_date": "2021-10-18T17:46:00",
"pickup_from_date": "2022-03-12T00:00:00",
"pickup_to_date": null,
"po_num": null,
"poster_id": null,
"shipper_id": null,
"status": "Completed",
"time_accepted": null,
"time_posted": "2021-10-19T00:47:24.060521",
"trailer_id": null,
"trailer_type": "Double",
"truck_id": "",
"weight": "1000"
},
]
you response.body is an Array . but you convert it again here:
List data = json.decode(response.body); // data is List<dynamic>
print(data); // it will return empty array
based on your postman response, response body is array, no need to json.decode if you assign the response to List data
what is decode do :
dynamic decode(String source, {Object? Function(Object?, Object?)?
reviver})
Parses the string and returns the resulting Json object.
decode require String not List. thats why based on your postman response it should throw an error if you do like this json.decode(response.body).
if you want to get the list without convert to Json Object all you have to do are remove json.decode
final data = response.body;
print (data); // if your api is success (200 ), this should not empty
// actually it same like
print(response.body);
Related
I would like help with a google apps script. I would like to connect a Google sheet to the Mailerlite API in order to add multiple subscribers.
I would like to post each individual row from the google sheet as a subscriber in Mailerlite.
I would like a google sheet updated with the log of API responses with each trigger.
Here is the code I am using but can't get it to work. Thanks for your help!
function postUsersData() {
function getDataFromSpreadsheet() {
var usersSheetId = 11111111 // // Put your SHEET ID here
var usersSheet = getSheetById(usersSheetId)
// Users data
var values = usersSheet.getDataRange().getValues()
return values.map(function(value) {
return makePayload(values[0], value)
})
}
function postDataToMailerlite(payload) {
// API data
var url = 'https://api.mailerlite.com/api/v2/groups/'
var token = 'xxxxxxxxxxxxxxxxx' // // Put your TOKEN here
var groupId = 11111111 // // Put your GROUP ID here
var groupUrl = url + groupId + '/subscribers/import'
var params = {
'method': 'POST',
'muteHttpExceptions': true,
'headers': {
'Authorization': 'apikey ' + token,
'Content-Type': 'application/json'
},
'payload': JSON.stringify({'subscribers': payload, 'resubscribe': false, 'autoresponders': true})
};
var response = UrlFetchApp.fetch(groupUrl, params)
return JSON.parse(response.getContentText())
}
function logAction(json) {
var logsSheetId = 11111111 // // Put your SHEET ID here
var logsSheet = getSheetById(logsSheetId)
var logsSheetValues = logsSheet.getDataRange().getValues()
var payload = {
'datetime': Date(),
'imported': json.imported.length,
'unchanged': json.unchanged.length,
'updated': json.updated.length,
'errors': json.errors.length,
'errors log': json.errors
}
Object.keys(payload).forEach(function(key) {
logsSheet.getRange(logsSheetValues.length + 1, logsSheetValues[0].indexOf(key) + 1).setValue(payload[key])
})
Logger.log('Done ' + Date())
}
function getSheetById(id) {
// Get sheet by ID
return SpreadsheetApp.getActive().getSheets().filter(
function(s) {return s.getSheetId() === id;})[0];
}
function makePayload(headers, value) {
// Make single user data JSON from data based on row number
return {
'email': value[headers.indexOf('email')],
'fields': {
'full_name': value[headers.indexOf('name')],
'job': value[headers.indexOf('job')],
'trigger': value[headers.indexOf('trigger')]
}
}
}
// Perform
const data = getDataFromSpreadsheet()
const response = postDataToMailerlite(data)
logAction(response)
}
I/flutter (30384): data {"type":"https://tools.ietf.org/html/rfc7231#section-6.5.1","title":"One or more validation errors occurred.","status":400,"traceId":"|e3244589-485510f2c271c42c.","errors":{"$.name":["'name, "surname": surname, "email": email, "plateNumber": plateNumber}' is an invalid JSON literal. Expected the literal 'null'. Path: $.name | LineNumber: 0 | BytePositionInLine: 11."]}}
Code here:
DataModel class
List<DataModel> dataModelFromJson(String str) =>
List<DataModel>.from(json.decode(str).map((x) => DataModel.fromJson(x)));
String dataModelToJson(List<DataModel> data) => json.encode(List<dynamic>.from(data.map((x) => x.toJson())));
class DataModel {
DataModel({
this.name,
this.surname,
this.email,
this.plateNumber,
});
int id;
String name;
String surname;
String email;
String plateNumber;
factory DataModel.fromJson(Map<String, dynamic> json) => DataModel(
name: json["name"],
surname: json["surname"],
email: json["email"],
plateNumber: json["plateNumber"],
);
Map<String, dynamic> toJson() => {
"name": name,
"surname": surname,
"email": email,
"plateNumber": plateNumber,
};
}
service class
Future<DataModel> submitData(String name, String surname, String email, String plateNumber) async {
try {
Uri uri = Uri.parse("http://ngcyaz.com/api/drivers");
String json = "{ \"name\": name, \"surname\": surname, \"email\": email, \"plateNumber\": plateNumber}";
Map<String, String> header = {"content-type": "application/json"};
var response = await http.post(uri, body: json, headers: header);
var data = response.body;
print("data " + data);
if (response.statusCode == 200) {
String responseString = response.body;
dataModelFromJson(responseString);
} else
return null;
} catch (e) {
print(e);
}
}
Use the simple map and pass it to jsonEncode
submitData(
String name, String surname, String email, String plateNumber) async {
try {
Uri uri = Uri.parse("http://ngcyaz.com/api/drivers");
final map = {
"name": name,
"surname": surname,
"email": email,
"plateNumber": plateNumber
};
Map<String, String> header = {"content-type": "application/json"};
var response = await http.post(uri, body: jsonEncode(map), headers: header);
var data = response.body;
print("data " + data);
if (response.statusCode == 200) {
String responseString = response.body;
print("Response String: " + responseString);
} else
return null;
} catch (e) {
print(e);
}
}
Please How Can I get this kind of API response in Flutter using http with FutureBuilder.
"GLODATA": {
"1000": {
"pname": "GLO 1.0GB/14days",
"price": "470",
"pld": "1000"
},
"1600.01": {
"pname": "GLO 2.0GB/30days",
"price": "940",
"pld": "1600.01"
},
"3750.01": {
"pname": "GLO 4.5GB/30days",
"price": "1900",
"pld": "3750.01"
},
"5000.01": {
"pname": "GLO 7.2GB/30days",
"price": "2430",
"pld": "5000.01"
}
},
I think in your case, you will need to do something like this:
Api:
Future<http.Response> getData() async {
final _api = "http://yourendpointhere";
http.Response response = await http.get(_api);
if (response.statusCode != 200) {
throw Exception("Request failed...");
}
return response;
}
Then consume your api:
http.Response response = await _apiInstance.getData();
if (response.body != null && response.body.isNotEmpty) {
String source = Utf8Decoder().convert(response.bodyBytes);
Map<String, Map<String, dynamic>> data = Map();
data = Map<String, Map<String, dynamic>>.from(json.decode(source));
}
After that, you can create a factory constructor in your model class, receiving that map and turning it into an instance of your class.
Using Google sheets, I have stored my api_key and api_secret in the Property service section of user info as respectively "api_key" and api_secret".
I want to get wallet info from my account. The code I have written is as follows:
function wallet() {
var api_key = PropertiesService.getScriptProperties().getProperty('api_key');
var api_secret = PropertiesService.getScriptProperties().getProperty('api_secret');
var response = UrlFetchApp.fetch("https://api.bitfinex.com/v2/auth/r/wallets", api_key, api_secret);
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("sheet");
var result = JSON.parse(response.getContentText());
var wallet_btc = result.BALANCE
}
When I run in debug mode the error message is:
Cannot find method fetch(string,null,null). (line 13, file "Code")
Is this approach wrong, the code wrong, or both?
Many thanks.
How about the following modifications?
Modification points :
The parameters for UrlFetchApp.fetch() are UrlFetchApp.fetch(url, params). And params is an object.
This is the reason of error Cannot find method fetch(string,null,null). (line 13, file "Code").
When I saw the sample scripts for Bitfinex API, the request body has to be created using api_key, api_secret, nonce, body and signature. And signature is encrypted by HMAC_SHA_384 and converted to the string of the unsigned hexadecimal.
The sample for the endpoint of https://api.bitfinex.com/v2/auth/r/wallets is as follows. This is from API reference.
Sample for the endpoint of https://api.bitfinex.com/v2/auth/r/wallets
request.post(
`${url}/auth/r/wallets`,
headers: { /* auth headers */ },
body: {},
json: true,
(error, response, body) => console.log(body)
)
When above points are reflected to your script, the modified script is as follows.
Modified script :
function wallet() {
var api_key = PropertiesService.getScriptProperties().getProperty('api_key');
var api_secret = PropertiesService.getScriptProperties().getProperty('api_secret');
var apiPath = "v2/auth/r/wallets";
var nonce = Date.now().toString();
var body = {};
var rawBody = JSON.stringify(body);
var signature = "/api/" + apiPath + nonce + rawBody;
signature = Utilities.computeHmacSignature(Utilities.MacAlgorithm.HMAC_SHA_384, signature, api_secret)
.map(function(e) {
var v = (e < 0 ? e + 256 : e).toString(16);
return v.length == 1 ? "0" + v : v;
}).join("");
var url = "https://api.bitfinex.com/" + apiPath;
var options = {
method: 'POST',
contentType: "application/json",
headers: {
'bfx-nonce': nonce,
'bfx-apikey': api_key,
'bfx-signature': signature
},
payload: rawBody
};
var response = UrlFetchApp.fetch(url, options);
var result = JSON.parse(response.getContentText());
Logger.log(result)
// var wallet_btc = result.BALANCE // I couldn't confirm whether this key exists.
}
References :
Sample scripts for Bitfinex API
API reference
UrlFetchApp.fetch()
I cannot confirm whether this works. If this didn't work, can you tell me the situation? I would like to modify.
Edit :
When you want 0.0957596 from the result of [["exchange", "USD", 14.81076629, 0, null], ["exchange", "BTC", 0.0957596, 0, null], ["funding", "BTC", 4.13E-6, 0, null], ["funding", "ETH", 3.50186961, 0, null], ["exchange", "OMG", 5.9E-7, 0, null]];, you can use the following script.
Script :
function wallet() {
var api_key = PropertiesService.getScriptProperties().getProperty('api_key');
var api_secret = PropertiesService.getScriptProperties().getProperty('api_secret');
var apiPath = "v2/auth/r/wallets";
var nonce = Date.now().toString();
var body = {};
var rawBody = JSON.stringify(body);
var signature = "/api/" + apiPath + nonce + rawBody;
signature = Utilities.computeHmacSignature(Utilities.MacAlgorithm.HMAC_SHA_384, signature, api_secret)
.map(function(e) {
var v = (e < 0 ? e + 256 : e).toString(16);
return v.length == 1 ? "0" + v : v;
}).join("");
var url = "https://api.bitfinex.com/" + apiPath;
var options = {
method: 'POST',
contentType: "application/json",
headers: {
'bfx-nonce': nonce,
'bfx-apikey': api_key,
'bfx-signature': signature
},
payload: rawBody
};
var response = UrlFetchApp.fetch(url, options);
var result = JSON.parse(response.getContentText());
// Logger.log(result)
// var wallet_btc = result.BALANCE // I couldn't confirm whether this key exists.
var balance = 0;
for (var i in result) {
if (result[i][0] == "exchange" && result[i][1] == "BTC") {
balance = result[i][2];
break;
}
}
Logger.log(balance)
}
Note :
From the document, it seems that the indexes of WALLET_TYPE, CURRENCY and BALANCE are always 0, 1 and 2 of each element in the response, respectively.
I am bound to the restrictions of my webservice: It expects a json-payload!
So, doing something like
var ajaxAppender = new log4javascript.AjaxAppender("clientLogger");
var jsonLayout = new log4javascript.JsonLayout();
ajaxAppender.setLayout(jsonLayout);
log.addAppender(ajaxAppender);
won't work, as it creates two keys in the forms-collection (data and layout).
How can I, with built-in options, get a json-payload?
I've created a JsonAppender
function JsonAppender(url) {
var isSupported = true;
var successCallback = function(data, textStatus, jqXHR) { return; };
if (!url) {
isSupported = false;
}
this.setSuccessCallback = function(successCallbackParam) {
successCallback = successCallbackParam;
};
this.append = function (loggingEvent) {
if (!isSupported) {
return;
}
$.post(url, {
'logger': loggingEvent.logger.name,
'timestamp': loggingEvent.timeStampInMilliseconds,
'level': loggingEvent.level.name,
'url': window.location.href,
'message': loggingEvent.getCombinedMessages(),
'exception': loggingEvent.getThrowableStrRep()
}, successCallback, 'json');
};
}
JsonAppender.prototype = new log4javascript.Appender();
JsonAppender.prototype.toString = function() {
return 'JsonAppender';
};
log4javascript.JsonAppender = JsonAppender;
used like so
var logger = log4javascript.getLogger('clientLogger');
var jsonAppender = new JsonAppender(url);
logger.addAppender(jsonAppender);
According to log4javascript's change log, with version 1.4.5, there is no longer the need to write a custom appender, if the details sent by Log4Javascript suffice.
1.4.5 (20/2/2013)
- Changed AjaxAppender to send raw data rather than URL-encoded form data when
content-type is not "application/x-www-form-urlencoded"
https://github.com/DECK36/log4javascript/blob/master/changelog.txt
Simply adding the 'Content-Type' header to the AjaxAppender and setting it to 'application/json' is enough
ajaxAppender.addHeader("Content-Type", "application/json;charset=utf-8");
A quick test using fiddler shows that log4javascipt sends a collection of objects. Here's a sample of the payload:
[{
"logger": "myLogger",
"timestamp": 1441881152618,
"level": "DEBUG",
"url": "http://localhost:5117/Test.Html",
"message": "Testing message"
}]