© The Author(s), under exclusive license to APress Media, LLC, part of Springer Nature 2021
V. GagliardiDecoupled Django https://doi.org/10.1007/978-1-4842-7144-5_4

4. Advantages and Disadvantages of Decoupled Architectures

Valentino Gagliardi1  
(1)
Colle di Val D’Elsa, Italy
 
In this chapter, we outline various approaches for decoupling a Django project. In particular, we cover:
  • Hybrid architectures

  • Fully decoupled architectures based on REST and GraphQL

  • Advantages and disadvantages of both styles

By the end of the chapter you should be able to discern and apply with success one or more decoupling styles to your next Django project.

Pseudo-Decoupled Django

Pseudo-decoupled, or hybrid decoupling , is an approach in which a static frontend is augmented with a sprinkle of JavaScript; just enough to make things interactive and playful for the end user.

In the next two sections, we go over the perks and drawbacks of a pseudo-decoupled setup by examining two different approaches: without REST and with REST.

Pseudo-Decoupled Without REST

Depending on how long you have been programming, you will begin to notice that there is a category of patterns recurring over and over when building web applications: data fetching and form handling.

For example, you might have a page for inserting new data in your Django application. How you handle data insertion is up to the user requirements, but basically you have two choices:
  • Handle the form exclusively with Django

  • Handle the form with JavaScript

Django forms and model forms are great with their ability to generate the fields for you, but most of the time we want to intercept the classic GET/POST/Redirect pattern of form handling, in particular the submit event of forms. To do so, we introduce a little JavaScript into the Django templates. Listing 4-1 shows such an example.
{% block script %}
   <script>
       const form = document.getElementById("reply-create");
       form.addEventListener('submit', function (event) {
           event.preventDefault();
           const formData = new FormData(this);
           fetch("{% url "support:reply-create" %}", {
               method: 'POST',
               body: formData
           }).then(response => {
               if (!response.ok) throw Error(response.statusText);
               return response;
           }).then(() => {
               location.reload();
               window.scrollTo({top:0});
           });
       });
{% endblock %}
Listing 4-1

JavaScript Logic for Form Handling

In this example, we tie JavaScript to the form so that when the user submits the data, the default event for the form is intercepted and stopped. Next up we build a FormData object, which is sent to a Django CreateView. Notice also how we can use Django’s url template tag to build the URL for Fetch. For this example to work, the form must have a CSRF token included, as shown in Listing 4-2.
<form id="reply-create">
   {% csrf_token %}
   <!-- fields here -->
</form>
Listing 4-2

Django’s CSRF Token Template Tag

If the token is outside the form, or for any other POST request not coming directly from the form, the CSRF token must be included in the XHR request header. The example outlined here is just one of the many use cases for JavaScript into a Django template. As touched briefly in Chapter 2, we are seeing a Cambrian explosion of micro-frameworks for adding just enough interactivity to Django templates. There is not enough space to cover every possible example in this book. Here we focus on the broader architecture to examine advantages and disadvantages of each approach. Figure 4-1 shows a representation of pseudo-decoupled Django without REST.
../images/505838_1_En_4_Chapter/505838_1_En_4_Fig1_HTML.png
Figure 4-1

A pseudo-decoupled Django project can have one or more apps, each with its own templates. JavaScript is blended into templates and talks to regular Django views

Keeping in mind what Django has to offer in terms of development speed, in the case of a pseudo-decoupled, or hybrid, approach, what do we gain and what do we lose?
  • Authentication and cookies: Since we serve JavaScript from within Django templates we don’t need to worry about complex authentication methods. We can use the built-in session auth. Also, in a pseudo-decoupled setup, cookies are free to travel over each request on the same domain.

  • Forms: Django has an amazing form system that saves tons of time during development. In a pseudo-decoupled setup, we can still use Django forms to build up the HTML structure for data insertion, with just enough JavaScript to make them interactive.

  • What JS library? In a pseudo-decoupled setup, we can use any lightweight frontend library that doesn’t require a build pipeline, such as Vue.js, or even better, vanilla JavaScript. If we know beforehand what user agent we’re going to target, we can serve modern JavaScript syntax without a transpilation step.

  • Routing: Django is in charge of routing and URL building. No need to worry about JavaScript routing libraries or weird issues with the back button of the browser.

  • Search engine optimization: For content-heavy websites, a pseudo-decoupled setup is often the safest choice, as long as we don’t generate critical contents dynamically with JavaScript.

  • Developer productivity/burden : In a hybrid setup, the amount of JavaScript is hopefully so low that we don’t need complex build tooling. Everything is still Django-centric, and the cognitive load for the developer is low.

  • Testing: Testing JavaScript interactions in the context of a Django application has been always tricky. Selenium for Python doesn’t support automatic waiting. There are a number of tools, mostly wrappers around Selenium, like Splinter, that have this capability. However, testing a pseudo-decoupled Django frontend without a JavaScript-capable test runner can be still cumbersome. Tools like Cypress, which we cover in Chapter 9, play really well with Django to ease the burden of testing JavaScript-enriched interfaces.

Pseudo-Decoupled with REST

Not every application must be architected as a single-page application, and since the beginning of this book we stressed this point.

Over-engineered applications are the root of all evil, to play along the lines of Donald Knuth. However, there are hybrid situations where the UI requires a lot of JavaScript interactivity, more than a simple form handling, but we still don’t want to leave Django’s umbrella. In these configurations you will find it reasonable to introduce JavaScript libraries like Vue.js or React into a Django project. While Vue.js is highly progressive, it doesn’t want to take control of all the page. React forces the developer to do everything in React. In these situations the Django frontend, made out of templates and augmented with Forms or Model Forms, can lose importance in favor of a pseudo-decoupled setup, whereby:
  • The frontend of one or more Django apps is built entirely with JavaScript

  • The backend exposes a REST API

The difference between such a setup and an architecture where the frontend is on a different domain/origin from the REST API is that in a pseudo-decoupled setup, we serve the SPA frontend and the REST API from within the same Django project. This has a number of positive side effects. Why introduce REST in such a setup? A Django CreateView and a Model work well up to a certain point, after which we don’t want to reinvent the wheel, like JSON serialization for models. Django REST paired with a modern frontend library is a solid ground for robust decoupled projects. Figure 4-2 shows a representation of pseudo-decoupled Django with REST.
../images/505838_1_En_4_Chapter/505838_1_En_4_Fig2_HTML.png
Figure 4-2

A pseudo-decoupled Django project with REST can have one or more apps, each with its own REST API. JavaScript is served as a single-page application inside the Django project and talks to Django REST views

In the next chapter, we see a practical example of a pseudo-decoupled setup with the Django REST Framework and Vue.js. Here, we cover advantages and disadvantages of a pseudo-decoupled configuration, as we did in the previous section for the REST-less setup.
  • Authentication and cookies: Session-based authentication is the default choice for a pseudo-decoupled project, even with REST. Since we serve the single-page application from within the same Django project, it’s only a matter of authenticating the user through a regular Django view and grabbing the appropriate cookies before making POST requests from JavaScript.

  • Forms: If we decide to build one or more Django applications as single-page applications, we lose the ability to use Django Forms and Model Forms. This begins to lead to code duplication and more work for the team, as good ’ol Django forms and their data validation layers must be reimplemented with the JavaScript library of choice.

  • What JS library? In a pseudo-decoupled setup with REST, we can use any JavaScript library or framework. This requires some extra steps to include the bundle in the Django static system, but it is possible with any library.

  • Routing: Routing for single-page apps served from within a Django project is not trivial to implement. Django can still serve the main path for each single app, something like https://decoupled-django.com/billing/ for example, but then each app must handle its internal routing. Hash-based routing is the simplest form of routing, and the easiest to implement, compared to history-based routing.

  • Search engine optimization: Single-page applications (SPAs) are ill-suited for content-heavy websites. This is one of the most important aspects to take into account before integrating an SPA into Django.

  • Developer productivity/burden: Any modern JavaScript library comes with its own set of challenges and tooling. In a pseudo-decoupled setup with REST and one or more single-page apps, the overhead for Python developers can increase exponentially.

  • Testing : In a pseudo-decoupled setup with a low amount of JavaScript ,it could make sense to use tools like Selenium or Splinter, taking into account the need to implement automatic waiting for JavaScript interactions. Instead, in a pseudo-decoupled configuration based on REST and a SPA, Python-centric tools fall short. To test JavaScript-heavy interfaces and JavaScript UI components such as those implemented with Vue.js or React, tools like Cypress for functional testing and Jest for unit testing are better choices.

Fully-Decoupled Django

Opposed to a pseudo-decoupled setup, a fully-decoupled architecture, also called headless, is an approach in which the frontend and the backend are completely separated.

On the frontend we can find JavaScript single-page applications living on a different domain/origin from the backend, which now serves as a source of data with REST or GraphQL. In the next two sections, we go over both approaches.

Fully-Decoupled with REST

Fully-decoupled Django projects with REST are by far one of the most widespread setups. Thanks to its high flexibility, the REST API and the frontend may be deployed on different domains or origins. The Django REST Framework is the de-facto library for building REST APIs in Django, while JavaScript leads the frontend with React, Vue.js, and Angular. In these configurations, the architecture is usually arranged as follows:
  • The frontend of one or more Django apps lives outside Django as a single-page JavaScript app

  • One or more Django apps expose a REST API

A Django project configured fully-decoupled with a REST API can serve wonderfully as:
  • A REST API for a SPA, a mobile app, or a Progressive Web App

  • A content repository for a static site generation tool (SSG) or for a server-side rendered JavaScript project (SSR)

Figure 4-3 shows a representation of fully-decoupled Django project with REST.
../images/505838_1_En_4_Chapter/505838_1_En_4_Fig3_HTML.png
Figure 4-3

A fully-decoupled Django project with REST can have one or more apps, each with its own REST API. JavaScript lives outside the Django project as a single-page application and talks to Django REST views through JSON

It’s important to note that not every Django app inside a project must expose a REST API: one could choose to decouple one or more facets of the application, while keeping the rest under the classic MVT arrangement. The separation of concerns prescribed by REST opens the road to flexible, but also more complex, setups. What can we expect if we decouple a Django project with REST?
  • Authentication and cookies: Authentication for fully-decoupled projects is not trivial to implement. Session-based authentication can work with REST and single-page apps, but it breaks the stateless constraint. There are a number of different approaches to circumvent the limitations of session-based authentication for REST APIs, but in later years the community seemed oriented to embrace stateless authentication mechanisms, such as token-based authentication with JWT (JSON web tokens). However, JWT is not so welcomed in the Django community due to its security flaws and potential implementation pitfalls.

  • Forms: Leaving Django templates and Forms means we lose the ability to build forms easily. In a fully-decoupled setup, the form layer is usually built entirely with JavaScript. Data validation often gets duplicated in the frontend, which now has to sanitize and validate the user input before sending requests to the backend.

  • What JS library? In a fully-decoupled setup with REST, we can use any JavaScript library or framework. There isn’t any particular constraint for pairing the Django REST backend with a decoupled frontend.

  • Routing: In a fully-decoupled setup, Django does not handle routing anymore. Everything weighs on the client’s shoulder. For single-page applications, one can choose to implement hash-based or history routing.

  • Search engine optimization: Single-page applications don’t play well with SEO. However, with the emergence of JavaScript static-site generators such as Gatsby, Next.js, and Nuxt.js, JavaScript developers can use the latest shiny tools to generate static pages from a headless Django project without the risk of harming SEO.

  • Developer productivity/burden: In a fully-decoupled setup with REST and one or more single-page apps, the work for Python developers increases by orders of magnitudes. For this reason, most Django and Python web agencies have a dedicated frontend team that deals exclusively with JavaScript and its related tooling.

  • Testing: In a fully-decoupled project, the frontend and the backend are tested separately. APITestCase and APISimpleTestCase help in testing Django REST APIs, while on the frontend we see again Jest and Cypress for testing the UI.

Fully-Decoupled with GraphQL

As with fully-decoupled Django with REST, a fully-decoupled Django project with GraphQL offers high flexibility, but also more technical challenges.

REST is a battle-tested technology. GraphQL on the other hand is pretty recent, but seems to offer some apparent advantages over REST. However, as with any new technology, developers and CTOs must assess carefully advantages and drawbacks before integrating new tools, and potentially new challenges, in production projects. Figure 4-4 shows a Django project decoupled with a GraphQL and a REST API.
../images/505838_1_En_4_Chapter/505838_1_En_4_Fig4_HTML.png
Figure 4-4

A fully-decoupled Django project can expose REST and GraphQL APIs. It’s not unusual to have both technologies in the same project

In Figure 4-4, we imagine a fully-decoupled Django project that exposes two different apps: one with REST and another with GraphQL. In fact, GraphQL can coexist with REST to enable progressive refactorings from a legacy REST API to a GraphQL endpoint. This is useful for assessing GraphQL before switching from REST or for exposing a GraphQL API for tools like Gatsby. What is the price to pay for embracing GraphQL? Let’s see.
  • Authentication and cookies: Authentication for GraphQL in fully-decoupled setups is mostly handled with token-based authentication. On the backend, GraphQL needs to implement mutations for handling login, logout, registration, and all the related corner cases.

  • What JS library? In a fully-decoupled setup with GraphQL, we can use any JavaScript library or framework. There isn’t any particular constraint for pairing the Django GraphQL backend with a decoupled frontend. GraphQL queries can be done even with Fetch or XMLHttpRequest.

  • Search engine optimization: GraphQL in the frontend is mostly used with client-side libraries like React. This means we cannot ship client-side generated pages as they are, or we would risk SEO damages. Tools like Gatsby, Next.js, and Nuxt.js can operate in SSG (static site generation) mode to generate static pages from a GraphQL API.

  • Developer productivity/burden: GraphQL is a novel technology and especially in the frontend there are literally a dozen ways to implement the data fetching layer. GraphQL seems to speed up developer productivity, but at the same time it introduces new things to learn and new patterns to take into account.

Since GraphQL is a data fetching layer, considerations for forms, routing, and testing do not differ from those of a decoupled REST project.

Summary

In this chapter we outlined various approaches to decoupling a Django project:
  • Pseudo-decoupled with and without REST

  • Fully decoupled with REST or GraphQL

Hopefully, you are now ready to make an informed choice for your next Django project. In the next chapter, we prepare our Django project before moving to JavaScript and Vue.js.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.144.97.189