Search code examples
javascriptpythonweb-servicesflaskweb-frontend

Call web service method on Flask server from javascript


I'm new to frontend development and website development; the goal is to call a webservice method on a server from web interface (client).

Context

I wrote a Python web service with Flask and I deployed it on my Raspberry Pi. I tested it with ngrok and Postman and it works fine, all the methods do exactly what they have to.
I have also a web server (Nginx) running on the Raspberry.
The Python web service is exposed on port 5000; Raspberry has IP 192.168.1.4.
addWord is a POST operation provided my the web service.
Finally, PC and Raspberry are on the same network.

Next step

I want to call a method of the Python web service from a frontend website, a simple HTML page, which I put on my web server.

My code

This is the code of my HTML page:

<head>
  <title>prova insert</title>
</head>

<body>
    <p id='text'></p>
  <script>
        var xhr = new XMLHttpRequest();
        var url = "http://192.168.1.4:5000/addWord";
        xhr.open("POST", url, true);
        xhr.setRequestHeader("Content-Type", "application/json");
        xhr.onreadystatechange = function () {
            if (xhr.readyState === 4 && xhr.status === 200) {
                var json = JSON.parse(xhr.responseText);
                console.log(json.email + ", " + json.password);
                text = document.getElementById("text");
                text.innerHTML = 'Ooooooooooooook';
            }
        };
        var data = JSON.stringify({"ita": "neve", "eng": "snow", "descr": "", "pos":"nome"});
        console.log(data);
        xhr.send(data);
  </script>
</body>

</html>

Flask code:

from flask import Flask
from flask import request
import json

import db_connection

app = Flask(__name__)


@app.route('/test')
def test():
    return "Test succeeded."

@app.route('/vocaboli')
def get_vocaboli():
    voc = connection.get_all_words()

    return json.dumps(voc)

@app.route('/addWord', methods = ['POST'])
def add_word():
    data = request.get_json()

    print(data)
    print(data.get('ita'))

    ita = data.get('ita')
    eng = data.get('eng')

    descr = data.get('descr') # opzionali
    pos = data.get('pos')

    connection.add_word(ita, eng, descr, pos)

    response = dict(correct='ok')
    return json.dumps(response)


if __name__ == '__main__':
    connection = db_connection.DatabaseConnection()
    app.run()

dbconnection.py:

class DatabaseConnection():
        def __init__(self):
                self.mariadb_connection = mariadb.connect(user=user, password=password, database='vocabulary')
                print('Connection succeeded.')

        def get_cursor(self):
                return self.mariadb_connection.cursor()

        def get_all_words(self):
                cursor = self.get_cursor()

                cursor.execute("select * from vocaboli")
                return cursor.fetchall()

        def add_word(self, ita, eng, descr=None, pos=None):
                cursor = self.get_cursor()
                cursor.execute("insert into vocaboli (ita, eng, description, pos) values ('{}', '{}', '{}', '{}')".format(ita, eng, descr, pos))
                self.mariadb_connection.commit()

        def update_description(self, ita, eng, descr=None):
                cursor = self.get_cursor()
                cursor.execute("update vocaboli set description = '{}' where ita = '{}' and eng = '{}'".format(descr, ita, eng))
                self.mariadb_connection.commit()

Output
enter image description here

I tried also to do POST on http://192.168.1.4/addWord, but it returns a NOT FOUND.


Question
How can I call the web service from the Javascript code in the proper way? Have I to use the ngrok tunnel as URL, or I have to use the IP of the Raspberry?
Have I to use PHP in some way to work on the server side?
As I said, I'm not familiar with Javascript/PHP, probably the answer is straightfoward but I can't figure it out.


Solution

  • By default, the Flask server is only accessible locally. As per the Flask documentation, try specifying host='0.0.0.0' when running your app to make it accessible from other devices in the network:

    if __name__ == '__main__':
        connection = db_connection.DatabaseConnection()
        app.run(host='0.0.0.0')
    

    Then try displaying the /test page from a browser on the PC (http://192.168.1.4:5000/test).

    If that doesn't do the trick, make sure port 5000 is open on your Raspberry Pi.

    Edit addressing the CORS policy error:

    Try using the flask_cors module to allow CORS:

    from flask import Flask
    from flask_cors import CORS
    
    ...
    
    app = Flask(__name__)
    CORS(app)
    
    ...