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.
Handle the form exclusively with Django
Handle the form with JavaScript
JavaScript Logic for Form Handling
Django’s CSRF Token Template Tag

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
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.
The frontend of one or more Django apps is built entirely with JavaScript
The backend exposes a REST API

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
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
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 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)

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
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.

A fully-decoupled Django project can expose REST and GraphQL APIs. It’s not unusual to have both technologies in the same project
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
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.