- Trying to access the always-on APIC-EM sandbox API using a webserver and javascript.
- Scenario:
- Got a locally hosted nodejs server. Using xmlHttpRequest (the nodejs version xhr ) able to run a GET command . However, since V1 and ticketing system demands to POST the username/password so that can get the ticket and run the GET commands for network device discovery etc..
- Problem:
- APIC-EM doesn't seem to recognize the header content type of 'application/json' when tried to POST (it does with GET). It returns an error of: "error code": "unknown", "message": "Content-type: 'text/plain;charset=UTF-8' not supported"
- Here is the code:
var json_text = '{ "username": "admin","password": "C!sc0123" }'; var ticket_json = JSON.parse(json_text); var apicem_ip = "sandboxapic.cisco.com:9443"; var apic_url = 'https://'+apicem_ip+'/api/v1/ticket'; //- var xmlHTTP = new XMLHttpRequest(); var XMLHttpRequest = require("xmlhttprequest").XMLHttpRequest; var xhr = new XMLHttpRequest(); xhr.open('POST',apic_url,false); xhr.responseType = 'JSON'; xhr.setRequestHeader = ('content-type', 'application/json'); xhr.send(JSON.stringify(ticket_json)); app.locals.apic_nd = xhr.responseText;
- Lines 6 and 12 are nodejs specific as XMLHttpRequest doesn't exist natively in nodejs. Line 12 is just setting a global variable to be called in the HTML file (which is where the responses and errors from the sandbox controller are viewed).
- Tried to send just a plain JSON object on line 11 (without the stringify function which converts it into a string), but that doesn't work in Java Script .That is not how the python API works either (it is a string as well).changed line 10 to 'text/json' as well, no luck.
- Already have a way to view the controller data via a shell using python, would like to call the APIs and see the same data via a browser and figured JavaScript would be the easiest way but ran into the above issue.
What might be happening is XMLHttpRequest is looking for a "Content-type" header with an uppercase 'C'. Since it doesn't see one, it goes with its default. Can you try setting the header Content-type and see if that helps. While this shouldn't matter, there have been bugs with this in the past with XMLHttpRequest modules.
If that doesn't work, the other thing it might be is complaining on the Accept header. Try also adding:
xhr.setRequestHeader('Accept','application/json');
- Tried both the options and still got the same error message.
Got a sniffer capture of the request to see what headers and body the client is sending.
modified the script .
var url = 'https:/sandboxapic.cisco.com:9443/api/v1/ticket';
// provide username and password as body of request
var j_data = {
"username":"admin",
"password":"C!sc0123"};
var json_text = '{"username":"admin","password":"C!sc0123"}';
var ticket_json = JSON.parse(json_text);
var xmlHttp = new XMLHttpRequest();
alert("test1");
xmlHttp.open("POST", url, false);
xmlHttp.setRequestHeader("Content-type", "application/json");
alert("test2");
xmlHttp.responseType = "JSON";
alert("test3");
// xmlHttp.send(JSON.stringify(j_data));
xmlHttp.send(JSON.stringify(ticket_json));
alert("test4");
alert(xmlHttp.response);
var data = JSON.parse(xmlHttp.response)
alert(data.version)
alert(data.response.serviceTicket);
}
xhr.setRequestHeader = ('content-type', 'application/json'); ==> got error.
vs
xhr.setRequestHeader('content-type', 'application/json');
Aslo we can just use
var json_text = { "username": "admin","password": "C!sc0123" };
......
......
xhr.send(JSON.stringify(json_text));
wonder why it worked with the GET requests.changed the code but still a no go. Looking at the xhr module there is a known bug for synchronous requests that mess up header data. changed the code to async which is supposed to fix it but still got the same error. The problem might be with the module.
Got it working with a different module,
var apicem_ip = "sandboxapic.cisco.com:9443";
var apic_url = 'https://'+apicem_ip+'/api/v1/ticket';
var request = require('request');
var options = {
url: 'https://'+apicem_ip+'/api/v1/ticket',
method: "POST",
headers: {
'Content-type': 'application/json'
},
//console.log("test1");
body: '{ "username": "admin", "password": "C!sc0123"}'
//console.log("test2");
};
function callback(error, response, body) {
console.log("callback function");
//if (!error && response.statusCode == 200) {
if (!error) {
var info = (JSON.parse(body));
console.log(info);
console.log("status 200");
}
else {
//console.log(response.statusCode);
//console.log(JSON.parse(body));
console.log(JSON.parse(body));
}
}
request.post(options, callback);
Node.js with express.js as the webfrontend. Also using jade as the HTML template option. Just downloaded a template website (google hackathon-startup).
The code above is the only real addition that is been made to app.js. Trying to figure out now how to incorporate the js code either directly into HTML via jade... or... directly into the controller js res handler. Again, new to node in general so still trying to figure it out.
I am trying this code JS as well
=================================
<html>
<head>
<title>
Hello.com
</title>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
</head>
<script>
var url = 'https://sandboxapic.cisco.com/api/v1/ticket';
// provide username and password as body of request
var json_text = {"username" : "devnetuser","password" : "Cisco123!"};
var x = JSON.stringify(json_text);
//var ticket_json = JSON.parse(json_text);
var xmlHttp = new XMLHttpRequest();
xmlHttp.withCredentials = true;
alert("test1");
xmlHttp.open("POST", url, true);
xmlHttp.setRequestHeader('X-PINGOTHER.com', 'pingpong');
xmlHttp.setRequestHeader("content-type", "application/json");
alert("test2");
xmlHttp.responseType = "json";
alert("test3");
xmlHttp.send(x);
//xmlHttp.send(json_text);
alert("test4");
var data = JSON.parse(xmlHttp.response);
//alert(data.version);
// alert(data.response.serviceTicket);
</script>
</html>
=====================================
having an issue with CORs. cant figure out the problem..
While running chrome CTRL+Shift +J (devtools)
Try setting a little timeout for the script to get the information from the server. Are you able to get the info immediately.
setTimeout(tst, 3000);
function tst () {
var data = JSON.parse(xmlHttp.responseText);
document.getElementById("demo").innerHTML = "The Ticket number is " + data.response.serviceTicket;
alert(data.version);
}
Nodejs is asynchronous so the timeouts and dealing with hangups are explicit in the architecture. I.e., it will call the request, then move on to other code, and then come back to the request as soon as there is a response.
using a back end server for requests is a bit of a work around.
Just tried with a Java Application and none of the cors issues. It seems to be a JS specific issue. Even the timeout is not necessary.
Comments
0 comments
Please sign in to leave a comment.