On a very high level, web applications tend to have two major parts: front end and back end. The back end is responsible for computing data and the front end is responsible for presenting that data to the users.
The front end primarily consists of a presentation layer for displaying and navigating between HTML pages. Whereas the back end consists of a data layer for retrieving data from a database or an external service and a business layer for performing operations on that data.
Traditional Web Applications
In a traditional web application, both front and back ends are implemented on the server-side. A request is sent from a browser to a server. The presentation layer intercepts the request and forwards it to a component in business layer responsible for fulfilling that request. If the business component needs to access data from a database or an external service, it’ll make that request to the data layer. The business layer returns the result of its computation to the presentation layer. The presentation layer then determines how to display that result and sends an HTML page back to the browser. The figure below shows this end-to-end interaction between a browser and the server-side components.
Single-Page Web Applications
Often times, after an application is loaded in a browser, all client-side wants to do is send or receive new data from a server. However, with the architecture shown above, the server has to send an entire HTML page back and not just the fresh data client is interested in. This is because the presentation layer sits on the server-side. Without this layer, the client is just a dumb terminal for requesting pages. What if we move the presentation layer to the client-side as shown below?
With the new architecture, the entire front end is loaded at once on the client-side. This enables the client to send and receive just the data it’s interested in and nothing more. It can send those requests asynchronously via ajax.
Instead of receiving a full HTML page as a response, the client now gets a JSON representation of the data it requested. (Although a response typically is in JSON format, it doesn’t have to be.) It then updates parts of the page that display the new data without having to reload the entire page. This approach reduces unnecessary overhead incurred by traditional web applications. This is essentially how most single-page applications (SPAs) work.
Note: There is a hybrid approach to building SPAs that offers partial rendering of pages on the server-side. Explaining how this approach works is out of scope for this book.
The term single-page might sound confusing at first. What it means is that it’s a shell that defines an overall layout of the application. This layout divides the application into multiple regions, for example header, footer, sidebar, and main content.
Whenever the user attempts to navigate from one part of the application to another, the application determines which region(s) needs to be refreshed. It will then swap the view that is currently being displayed in that region with a new view. During the initial load, the client side fetches all views in the application along with the shell. It has to do that because in an SPA architecture, the entire presentation layer is moved to the client side.
Of course the application doesn’t display all of those views at the same time. It will wait for the right conditions to be met before showing a particular view. This mechanism is what enables SPAs to present rich user interfaces without having to retrieve a new page from the server every time the user attempts to navigate to a different part of the application.
Our Front End
The Elm app we’ll be building in this chapter is a SPA. It’ll be rendered fully on the client-side. This drastically simplifies the server-side implementation. However, all of that presentation complexity is now shifted over to the client-side. Luckily, Elm provides a robust architecture for structuring client-side applications no matter how complex they are.
Our Back End
The architectural diagram shown in the Single-Page Web Applications section above is a gross oversimplification of how back end apps are architected. Depending on how complex the app is, you may want to follow the guidelines set forth by a well-established architectural pattern such as Functional Core Imperative Shell, Clean Architecture or Domain Driven Design.
We won’t be using any of those patterns for our back end because it’s a very simple JSON server designed to serve data from a file. We created this server in the Decoding JSON - Part 1 section in chapter 6. All interactions between our front and back ends will occur via APIs only. The table below shows all the API end points our Elm app will be using to send and receive data.
|Action||Endpoint||HTTP Method||Full URL|
|Fetch all posts||
|Create a new post||
|Edit a post||
|Delete a post||
Because our front and back ends are fully decoupled, we won’t have to modify the back end at all if we ever decide to port our Elm app to other platforms, for example iOS or Android. An iOS or Android app can replicate the functionality in our Elm app by using the exact same APIs provided by the back end. Similarly, we also don’t have to modify the front-end apps if we ever decide to port our back end to a different platform as long as the APIs remain the same.