cancel
Showing results for 
Search instead for 
Did you mean: 
cancel
4362
Views
0
Helpful
18
Replies

APIC-EM API using javascript

Joshua Leatham
Cisco Employee
Cisco Employee

I am trying to access the always-on APIC-EM sandbox API using my webserver and javascript.  I have already done the python based learning labs and didn't have much issue with it.

Scenario:

I have a locally hosted nodejs server.  I am using xmlHttpRequest (the nodejs version xhr actually) and I can run a GET command no problem.  However, since V1 and the new ticketing system, I need to be able to POST the username/password so that I can get the ticket and run the GET commands that I want (network device discovery etc). 

Problem:

APIC-EM doesn't seem to recognize the header content type of 'application/json' when I POST (it does with GET, no problem).  It returns an error of: "error code": "unknown", "message": "Content-type: 'text/plain;charset=UTF-8' not supported"

Here is my 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.  I don't think that is a problem because I can successfully use GET and receive a response from the sandbox controller.  Line 12 is just setting a global variable to be called in my HTML file (which is where I view the responses and errors from the sandbox controller).

Things I've tried, I 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 and I believe that that is not how the python API works either (it is a string as well).  I also changed line 10 to 'text/json' as well, no luck. 

Why am I trying to do this?

I already have a way to view the controller data via a shell using python, I would like to call the APIs and see the same data via a browser.  I figured JavaScript would be the easiest way but ran into the above issue.

Any help would be appreciated.

18 Replies 18

Joe Clarke
Cisco Employee
Cisco Employee

I think 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');

I tried both your options and still got the same error message. 

Thanks for your input, any other ideas?

Can you get a sniffer capture of the request to see what headers and body the client is sending?

yawming
Cisco Employee
Cisco Employee

I tried yours and got

Then I modified my script to be the same as your then got

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);

}

I suspect there may have hidden char in you script or I missed something.

BUT those are minor compare to what you can see from the  last image that we are facing CORS issue. How can you resole the CORS issue that's the challenge.

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));

Heh, I didn't catch that.  Yeah, it's a method.  It doesn't return a settable property.

Hmm, nice catch! I wonder why it worked with the GET requests. I changed the code but still a no go. Looking at the xhr module I am using, there is a known bug for synchronous requests that mess up header data. I changed the code to async which is supposed to fix it but still got the same error. I think the problem might be with the module. There is another one I can try and will post back tomorrow or tonight. Thanks so far!

Joshua Leatham
Cisco Employee
Cisco Employee

I got it working with a different module, not sure why I was using the old one...guess I am new to nodejs and restAPIs.  Here is the code (this website won't let me format code in replies...)

Thanks for y'alls help!!

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);

Glad to hear that, so you did not get any CORS issue ?

Not sure what CORS is, but I was able to get a ticket number... so now it is on to the next where I use the ticket number as a header in my GET requests...like in the python modules.

I wonder if you can share your whole javascript ? You use node.js right ?

https://www.w3.org/TR/cors/

Yes. Node.js with express.js as the webfrontend. I am also using jade as the HTML template option. I am all new to this, I just downloaded a template website (google hackathon-startup).

The code I posted above is the only real addition I've made to app.js. However, I don't think that is where the code should live. I am 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.

Hi Guys

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>

=====================================

I think I am having an issue with CORs. cant figure out the problem

Here's what i get when I run chrome CTRL+Shift +J (devtools)