Update the Browser view (Front end) with endpoint calls

Hi everyone, I’m working on an application created with Django and I’ve run into a problem that is impossible for me to solve. I’m adding a chatbot to the web, more specifically the RASA chatbot, and the problem in a nutshell is that I want to make requests to Django endpoints, so that the corresponding function in the views.py file is called and render or redirect to the desired page from the browser.

I can’t do this from the frontend itself because I generate the request from the Rasa Server, and I can’t return this information to the Frontend or read it from there, because the frontend connects to the Server through a Github widget (rasa-webchat) that connects through Sockets (socket.io), which doesn’t allow passing extra information through Sockets or accessing the Socket object that is connected to the Server.

I have managed to pass the Session cookie and the CSRF protection cookie to the Server, and I have added them to the requests I make from Rasa. I thought that would be enough, but it was not. Now I get it to call the endpoint and correctly detect the Django user, but I can’t get it to update the view in the Browser.

From what I have investigated the problem could be of the WSGIRequest object of Django, that is always passed as first parameter to all the functions of views.py. This I believe that it is generated automatically with the request and I believe that with that object it knows to which Browser it must update the view if render() or redirect() is called.

To give you a better understanding, as an example, I tried to call the logout/ endpoint from Rasa:

class ActionLogout(Action):
    
    def name(self) -> Text:
        return "action_logout"

    def run(self, dispatcher: CollectingDispatcher,
            tracker: Tracker,
            domain: Dict[Text, Any]) -> List[Dict[Text, Any]]:

        requests.get(domainUrl + "logout/", params={"csrfmiddlewaretoken":tracker.get_slot("csrfmiddlewaretoken")},
                     cookies={"sessionid":tracker.get_slot("sessionid"),"csrftoken":tracker.get_slot("csrftoken")})

        if (requests): # successful response
            dispatcher.utter_message(text="The session has been successfully closed")
        else:
            dispatcher.utter_message(text="An error has occurred")

        return []

Which is declared like this:

urlpatterns = [
    path('admin/', admin.site.urls),
    path('', index, name="home"),

    # Users
    path('login/', login_view, name="login"),
    path('signup/', signup_view, name="signup"),
    path('logout/', logout_view, name="logout"),
...

And it calls the following function:

def logout_view(request):
    logout(request)
    return redirect('home')

When calling the endpoint it accesses the logout function and executes it perfectly, but it does not redirect home ('home' refers to index.html, and in the code it detects it correctly).

The endpoints are declared in the urls.py file inside the Django Project and the views.py are declared inside a Django App called DataVisualization, which is declared in the INSTALLED_APPS in settings.py of the project.

image

I understand that for it to work I need to pass some extra information to the request so that it knows which browser to go to. Can someone please help me? I’m really stuck…

I’m having trouble understanding what’s communicating with what.

What I’m understanding you to say is that the situation is this:

Browser[page containing websocket code] < -- > RASA < -- > Your Django server
where the first connection (browser with RASA) is a websockets connection and the second connection (RASA to Django server) is an http (or https) connection.

Is this correct? Does your browser ever request data directly from the Django server?

Your reading of the WSGIRequest object isn’t quite accurate. Neither your browser (or the RASA server) are creating these objects directly.

When a browser (or program, e.g. “requests”) makes a request to a web server, it’s opening up a TCP socket with that server. That socket stays open for the entire duration of the request/response process. The response is made back through that same socket. There’s no “choice” or “selection” made on the part of the server. Whatever program opens up that socket will receive the response.

Good morning, thank you for your reply. You have perfectly understood the connections. The problem is with the last connection, as I need the Django server to communicate with the Browser, but for that I think I need to pass some extra information in the communication from Rasa to Django.

Browser[page containing websocket code] < -- > RASA[extra information needed in request?] < -- > Django server[error: does not render the browser] < -- > Browser

The browser never requests any data directly from the Django server.

In the end I managed to solve the problem using the widget (which is the communication channel between Browser and Rasa). The widget I use provides a listener method to know when a communication has been received on the socket. For now, with this method I get the received text and react accordingly. Although this solves my problem, I’m still curious if there is a way to indicate to which Browser (or browser tab) Django should send a response.

I guess the only way would be to access the TCP socket that is created between the server and the Browser.

Thanks again!

If there is no direct connection between Django and the browser, then Django will be unable to directly send data to the browser.

You would have to send the data from Django back to RASA, and have it encapsulate the HTML into a websockets frame to be returned to the browser. The JavaScript hadling the websocket in the browser would then need to de-encapsulate the HTML and use it to update the DOM.