Search code examples
javascriptpostgetxmlhttprequest

GET request after a POST request is complete


In my project, I need to register a user in the db (POST request) through custom APIs.

Once that operation has been completed, I would like to make a GET request to get all users and pass the newly created information (e.g. id and others) to the next state (I am developing a game with the Phaser framework).

What I am trying to do is to use the callback in the post request to then call the other function that retrieves all the players again, but of course it doesn't work because they are async operations (although I thought I could solve it through callbacks).

These are my 2 functions:

saveNewUser: function(name, password){
var self = this;

    if(name && password){
        // create new calibration data for the current user
        var xhttp = new XMLHttpRequest();
        xhttp.open("POST", "https://project.herokuapp.com/api/users",true);
        xhttp.setRequestHeader("Content-Type", "application/json;charset=UTF-8");
        var input = JSON.stringify({
            "name": name,
            "password": password,
        });

        xhttp.onreadystatechange = function() {//Call a function when the state changes.
            if(xhttp.readyState == 4 && xhttp.status == 200) {
                console.log(xhttp.responseText);
                self.retrieveNewUser(name);
            }
        };

        xhttp.send(input);
    } else {
        self.errorMessage.visible = true;

        // make text become not visible again after few seconds
        self.time.events.add(Phaser.Timer.SECOND * 3, function () {
            self.errorMessage.visible = false;
        }, this);
    }
}

And the function that gets called inside:

retrieveNewUser: function (name) {
var self = this;

    // save user details in the global variables, get user after registration in db
    var xhr  = new XMLHttpRequest();
    xhr.open('GET', 'https://duchennegame.herokuapp.com/api/users', true);
    xhr.onload = function () {
        var users = JSON.parse(xhr.responseText);
        if (xhr.readyState == 4 && xhr.status == "200") {
            var userFound = false;

            users.forEach(function(user){
                if(user.name === name){
                    // save user details in the global variables
                    self.game.global.currentUser = user;

                    self.state.start('welcome');
                    userFound = true;
                }
            });

            // if user has not been found / wrong password, display error message
            if(!userFound){
                self.errorMessage.setText('Problem in retrieving the current user');
                self.errorMessage.visible = true;

                // make text become not visible again after few seconds
                self.time.events.add(Phaser.Timer.SECOND * 3, function () {
                    self.errorMessage.visible = false;
                }, self);

            }
        } else {
            console.error(users);
        }
    };
    xhr.send(null);
}

How do you make sure that the GET request is executed only AFTER the POST one has been completed?

EDIT

I realized that this code is never executed, so even the console message is not printed:

xhttp.onreadystatechange = function() {//Call a function when the state changes.
            if(xhttp.readyState == XMLHttpRequest.DONE && xhttp.status == 200) {
                console.log(xhttp.responseText);
                self.retrieveNewUser(name);
            }
        };

However, in this page they provide an example written in such a way. Is there something I am missing?


Solution

  • Question. Do you need to call retrieveNewUser in order to execute "xhttp.send(input);" ?

    If not, I would suggest you wrap the saveNewUser function in a promise. Promises are basically a more advanced form of callbacks that allow you to make asynchronous code execute more synchronously.

    So your saveNewUser function would look like this:

    saveNewUser: function(name, password){
    var self = this;
    
    //Returns Promise Object
    return new Promise(function(resolve, reject) {
    
        if(name && password){
            // create new calibration data for the current user
            var xhttp = new XMLHttpRequest();
            xhttp.open("POST", "https://project.herokuapp.com/api/users",true);
            xhttp.setRequestHeader("Content-Type", "application/json;charset=UTF-8");
            var input = JSON.stringify({
                "name": name,
                "password": password,
            });
    
            xhttp.onreadystatechange = function() {//Call a function when the state changes.
                if(xhttp.readyState == 4 && xhttp.status == 200) {
                    console.log(xhttp.responseText);
                    //This line of code essentially acts as a return statement
                    resolve(name);
                }
            };
    
            xhttp.send(input);
        } else {
            self.errorMessage.visible = true;
    
            // make text become not visible again after few seconds
            self.time.events.add(Phaser.Timer.SECOND * 3, function () {
                self.errorMessage.visible = false;
            }, this);
        }
    })};
    

    From there, you can run both functions in a synchronous manner by chaining the promises and running this statement:

    saveNewUser(name, password)
    .then(function(name){
    retrieveNewUser(name);
    });
    

    The then function takes a callback as a parameter. The callback receives the data that was resolved (in this case, name) and does something with it (in this case, calls retrieveNewUser).

    This ensures that retrieveNewUser() doesn't run until saveNewUser is finished.