javascriptjsonxmlhttprequestelixirelixir-poison

Retrieving response payload elements from XMLHttpRequest


I'm sending a JSON request (an applicative login but the kind of request doesn't matter) to a server with the following function:

function login() {
    var payload = {
    "api_key" : "", "cmd" : "login",
    "params" : {}
    }
    payload["params"]["username"] = document.getElementById("uname").value
    payload["params"]["password"] = document.getElementById("passwd").value

    var xhr = new XMLHttpRequest();
    xhr.open("POST", "http://localhost:4000/api", true);
    xhr.setRequestHeader("Content-type", "application/json");
    xhr.setRequestHeader("Accept", "application/json");

    xhr.onreadystatechange = function() {
        if (xhr.readyState == 4) {
            resp = JSON.parse(xhr.responseText);
            console.log("resp.status=" + resp.status);
            console.log("resp.[\"status\"]=" + resp["status"]);
        }
    }
    xhr.send(JSON.stringify(payload));
}

I'm actually getting the correct reply in the responseText field. For example, if the credentials are wrong, I get

{
  "status": "ko", 
  "errors": [
    {
      "cmd": "login",
      "long": "Login error : 'user-20' has no access to the system",
      "short": "login_error"
    }
  ]
}

If the credentials are OK I get

{
  "status": "ok",
  ... some additional data
}   

Yet, I can't manage to get the status field : resp.status or resp["status"] are always undefined. Same if the call is done in asynchroneous mode (xhr.open("POST", "http://localhost:4000/api", false);) or if I don't JSON.parse() the reply, ie: resp = xhr.responseText;.

Update - 2017.09.06

I finally found a way to get it working, but I don't quite understand why it is so. I actually changed

resp = JSON.parse(xhr.responseText);

into

resp = JSON.parse(JSON.parse(xhr.responseText));

To figure this out, I printed typeof(xhr.responseText) which is a sting. Actually typeof(JSON.parse(xhr.responseText)) is also a string and this is why it has no fields like status. Eventually, parsing xhr.responseText twice gives an object from which I actually can retrieve my data.

If somebody has a clue about what is happening, I would be interested... I don't know if this is related, but the app server that is sending the JSON is the latest version of Elixir/Phoenix, ie, 1.5/1.3 and JSON encoding/decoding is done with poison.


Solution

  • This is because you have assigned the resp variable to responseText

    resp = JSON.parse(xhr.responseText);

    To get the response code

    respCode = xhr.status

    Or if you want both in the same resp variable you could do

    resp = {
        responseText: xhr.responseText,
        status: xhr.status
    }
    

    Then you can access them as resp.responseText and resp.status