Reader small image

You're reading from  Building SPAs with Django and HTML Over the Wire

Product typeBook
Published inAug 2022
PublisherPackt
ISBN-139781803240190
Edition1st Edition
Tools
Right arrow
Author (1)
Andros Fenollosa
Andros Fenollosa
author image
Andros Fenollosa

Andros Fenollosa is a custom programming expert that works as a teacher, full stack developer, and mobile developer. He's a Web Designer, Web Programmer, and Apps Programmer, among other things ( PWA, Android and iOS ). He has a plethora of commercial expertise, having worked on projects in a variety of locales throughout the world.
Read more about Andros Fenollosa

Right arrow

Chapter 6: Creating SPAs on the Backends

We cannot create a complete site by simply managing groups and sending HTML to the client. We must first master a variety of small solutions in order to be able to build a dynamic page that interacts with the user, with essential features such as page switching!

When the first single-page applications (SPAs) were created, the developers at the time were forced to spend many hours on functionalities that had been free when using the HTTP protocol: routing, sessions, authentication, or origin verification, among others. Poor them! They had to re-invent the wheel with a rebellious adolescent JavaScript that was not very cross-browser compatible. However, they survived, or so I would like to think, by defining techniques in the frontend that have managed to mimic the same behavior as HTTP; these techniques have lasted until today. For example, in a routing system, when a SPA redraws a screen, the browser URL is modified to put the user in context...

Technical requirements

All the code from the different sections can be found at the following link:

https://github.com/PacktPublishing/Building-SPAs-with-Django-and-HTML-Over-the-Wire/tree/main/chapter-6

Switching between pages

At some point, the user will need to go to another page or change context. We are going to make them think this is happening, but in reality, it is going to be a magic trick since really, they will never move from the first HTML we gave them at the beginning. However, and here’s the key, they will perceive that the page is being changed. To achieve this deception (sorry, achievement), we will carry out the following tasks:

  1. Change the HTML of the main content or everything that belongs to <main>. Meanwhile, we will always keep the static sections of the pages, such as <header>, <aside>, or <footer>.
  2. Implement server-side rendering to render the HTML belonging to each URL.
  3. Visually mark in the <nav> where we are with a CSS style.
  4. Modify the browser URL via the JavaScript API. It is an aesthetic change but the URL acts as breadcrumbs to guide the visitor.

The objective is to build a site with three...

Server-side rendering for each route

After preparing the Consumer class to change pages dynamically, we are going to incorporate a trivial system with Django for the management of routes and the rendering of each page without depending on Channels, so that crawlers can index the content. We’ll define three templates (home.html, login.html, and signup.html).

The content of app/app_template/templates/pages/home.html will be a few lines of HTML:

<section>
    <h1>Welcome to an example of browsing with WebSockets over the Wire.</h1>
    <p>You will be able to experience a simple structure. </p>
</section>

Then, on the second page, representing a login form, we will use a form object to list all the fields and then validate. This will be an argument that we will pass when rendering the template.

We write the following code in app/app_template/templates/pages/login.html:

<h1>Login<...

Including a browser to achieve dynamic navigation

After incorporating the templates, views, and routes for traditional navigation, we will create a dynamic navigation system.

We declare a file in the app/app_template/components/_nav.html path with the following content:

<ul class="nav__ul">
    <li>
        <a
                href="#"
                class="nav__link nav__link nav__link--
                    page{% if active_nav == "home" %} 
                        active{% endif %}"
 ...

Changing URLs

We have managed to change pages and visually mark in the browser where we are, but the browser URL is still passive. We are going to add a mechanism to update the path every time we change pages.

In JavaScript, we can use the History API to manipulate the address that the visitor sees in the browser. For example, if you wanted to show that you are at /login/, you would implement the following:

history.pushState({}, '', '/login/')

What we will do is modify the event listener message by adding the line we just mentioned, together with a new parameter that will always send a Consumer class called url:

// Event when a new message is received by WebSockets
myWebSocket.addEventListener("message", (event) => {
    // Parse the data received
    const data = JSON.parse(event.data);
    // Renders the HTML received from the Consumer
    const selector =...

Hydrating sections or components

Although we have a function that can dynamically include HTML rendered from a template and apply it to a tag present in the document, we cannot decide whether we want to replace or insert HTML, in other words, hydrate or replace the DOM.

Hydration is a technique in web development where client-side JavaScript converts a static HTML web page into a dynamic web page by attaching event handlers to the HTML elements. This allows for a fast First Contentful Paint (FCP) but there is a period of time afterward where the page appears to be fully loaded and interactive. However, it is not until the client-side JavaScript is executed and event handlers have been attached.

To solve this problem, we will start by remembering that the Consumer class is prepared to receive the append instruction:

    def send_html(self, event):
        """Event: Send html to client"""...

Creating temporary sessions for clients

To have unique sessions for each client, we will need to activate middleware that enables this feature. Channels provides us with SessionMiddlewareStack or AuthMiddlewareStack, which also include tools to build login or logout functionality. We will use AuthMiddlewareStack whenever we can.

We edit project_template/asgi.py as follows:

import django
 
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "project_template.settings")
from django.conf import settings
django.setup()
from django.core.asgi import get_asgi_application
from channels.auth import AuthMiddlewareStack
from channels.routing import ProtocolTypeRouter, URLRouter
from django.urls import re_path
from app.app_template.consumers import ExampleConsumer
 
 
application = ProtocolTypeRouter(
    {
        # Django's ASGI application to handle traditional HTTP requests
     ...

Avoiding cross-site request forgery (CSRF) with WebSockets

By using sessions, we are exposing users to a CSRF attack unless we put appropriate measures in place.

CSRF attacks

CSRF attacks are malicious attacks on a website in which unauthorized commands are sent from one user to a second site with hidden forms, AJAX requests, or any other method in a hidden way.

You can find a reference here: https://en.wikipedia.org/wiki/Cross-site_request_forgery.

Channels provides a tool that will help us to avoid this type of attack in a simple way:

  1. We define the allowed Hosts in project_template/settings.py. In our case, we are using environment variables inside Docker:
    ALLOWED_HOSTS = os.environ.get("ALLOWED_HOSTS"). split(",")
  2. We edit project_template/asgi.py, by importing OriginValidator. We must pass two parameters: URLRouter (or any intermediary middleware) and the Hosts we want to protect:
    # project_template/asgi.py
    import django
     
    os.environ.setdefault...

Summary

In this chapter, we have added some very interesting new capabilities to our project: switching between pages, creating server-side rendering versions of each path, creating a dynamic page, modifying URLs, updating specific sections, working with sessions, and avoiding CSRF with WebSockets.

We now already have the basic skills to build a dynamic site with database access, group management, partial or full HTML rendering, event control that triggers backend actions, form creation, and some security measures. One question may be echoing in your head: was it worth all the effort? Just think that we can now create SPAs with minimal use of JavaScript, we don’t need to build an API to connect the frontend and the backend, and the time between requests and their responses is ridiculously low, avoiding the use of loading in many cases. The complexity of the projects also has decreased and we can avoid the installation of several frontend libraries. Judge for yourself. The...

lock icon
The rest of the chapter is locked
You have been reading a chapter from
Building SPAs with Django and HTML Over the Wire
Published in: Aug 2022Publisher: PacktISBN-13: 9781803240190
Register for a free Packt account to unlock a world of extra content!
A free Packt account unlocks extra newsletters, articles, discounted offers, and much more. Start advancing your knowledge today.
undefined
Unlock this book and the full library FREE for 7 days
Get unlimited access to 7000+ expert-authored eBooks and videos courses covering every tech area you can think of
Renews at $15.99/month. Cancel anytime

Author (1)

author image
Andros Fenollosa

Andros Fenollosa is a custom programming expert that works as a teacher, full stack developer, and mobile developer. He's a Web Designer, Web Programmer, and Apps Programmer, among other things ( PWA, Android and iOS ). He has a plethora of commercial expertise, having worked on projects in a variety of locales throughout the world.
Read more about Andros Fenollosa