I'm building a flutter application that talks to a Particle Photon device through the Particle Cloud and I'm having trouble making a correctly formatted request to the Particle cloud.
When I try to send my request with the particle Access Token encoded as form data, my code looks like this:
void setStatus(int idx) async {
print('ParticleService: setStatus($idx)');
var url = particleHost + _deviceID + particleVerb1;
var formData = 'access_token=$_accessToken¶ms=$idx';
var bodyLen = formData.length;
var headers = {
"Content-Type": "application/x-www-form-urlencoded",
"Content-Length": "$bodyLen"
};
var response = await http.post(url, body: formData, headers: headers);
}
With it, I get an error indicating that it can't find the Access Token:
Response body: {"error":"invalid_request","error_description":"The access token was not found"}
When I try to send the access token in an authorization header it looks like this:
var url = particleHost + _deviceID + particleVerb1;
var body = json.encode({"params": "$idx"});
var bodyLen = body.length;
var headers = {
HttpHeaders.authorizationHeader: _accessToken,
HttpHeaders.contentTypeHeader: 'application/json',
"Content-Length": "$bodyLen"
};
print('URL: $url');
print('Body: $body');
print('Headers: $headers');
var response = await http.post(url, body: body, headers: headers);
The particle cloud replies that the auth header is malformed:
Response body: {"error":"invalid_request","error_description":"Malformed auth header"}
I've done this many times before and it worked fine, but something about the Flutter implementation is killing me. Here is it in TypeScrtipt in an Ionic application:
setStatus(currentStatus: number): Promise<any> {
console.log(`ParticleService: setStatus(${currentStatus})`);
const url: string = PARTICLE_HOST + this.deviceID + PARTICLE_VERB_1;
const body = `access_token=${this.accessToken}¶ms=${currentStatus}`;
const headers: any = {
'Content-Type': 'application/x-www-form-urlencoded',
'Content-Length': body.length
};
return new Promise((resolve, reject) => {
this.http.post(url, body, { headers }).subscribe(data => {
resolve(data);
}, error => {
console.error(error.message);
reject(error.message);
});
});
}
Here it is in JavaScript for the browser:
console.log(`setRemoteStatus(${btnName})`);
// Get the color code based on the status being set
let colorCode = buttons.indexOf(btnName);
// Build the URL we'll use to talk to the Particle API
let postURL = particleHost + particlePath + config.getDeviceID() + particleVerb1;
// Craft the POST request body
let postBody = `access_token=${config.getAccessToken()}¶ms=${colorCode}`;
// Call the API
fetch(postURL, {
method: 'POST',
mode: 'cors',
headers: {
'Content-Type': "application/x-www-form-urlencoded",
"Content-Length": postBody.length
},
referrerPolicy: 'no-referrer',
body: postBody
}).then(res => {
if (res.status == 200) {
displayAlert('Status Update', 'info', 'Successfully set remote status', 500);
} else {
displayAlert('Update Error', 'warning', `Status not set (result code ${res.status})`);
}
}).catch(err => {
console.error('Unable to set status');
displayAlert('Update Error', 'error', `Unable to set status (${err.message})`);
});
Can someone please help me understand where I'm going wrong in the Dart code?
Change setStatus
to this:
Future<void> setStatus(int idx) async {
print('ParticleService: setStatus($idx)');
var url = particleHost + _deviceID + particleVerb1;
var formData = <String, String>{
'access_token': _accessToken,
'params': idx.toString(),
};
var response = await http.post(url, body: formData);
}
Don't try to encode the body yourself, when post
will do it for you if you give it a Map<String, String>
. (It also sets the content type and content length for you. If you need to add other headers you can re-instate the headers
map, but that's not needed if you just need the two content headers.)