A common MEAN stack architecture
A common way to architect a MEAN stack application is to have a representational state transfer (REST) API feeding a single-page application (SPA). The API is typically built with MongoDB, Express, and Node.js, with the SPA being built in Angular. The approach is particularly popular with those who come to the MEAN stack from an Angular background and are looking for a stack that gives a fast, responsive API. Figure 2.1 illustrates the basic setup and data flow.
What is a REST API?
REST stands for REpresentational State Transfer, which is an architectural style rather than a strict protocol. REST is stateless – it has no idea of any current user state or history.
API is an abbreviation for application program interface, which enables applications to take to each other.
So a REST API is a stateless interface to your application. In the case of the MEAN stack, the REST API is used to create a stateless interface to your database, enabling a way for other applications to work with the data.
Figure 2.1 is a great setup, ideal if you have or intend to build an SPA as your user-facing side.
- Angular is designed with a focus on building SPAs, pulling in data from a REST API, as well as pushing it back.
- MongoDB, Express, and Node.js are also extremely capable when it comes to building an API, using JSON all the way through the stack, including the database itself.
This is where many people start with the MEAN stack, looking for an answer to the question, "I've built an application in Angular; now where do I get the data?"
Looking beyond SPAs
Let's take a brief look at some things to bear in mind about SPAs when designing a solution and deciding whether a full SPA is right for your project or not.
Hard to crawl
Making an SPA crawlable
There are a couple of workarounds to make it look as though your site is crawlable. Both involve creating separate HTML pages that mirror the content of your SPA.
Analytics and browser history
Analytics tools like Google Analytics rely heavily on entire new pages loading in the browser, initiated by a URL change.
After the first page load, all subsequent page and content changes are handled internally by the application. So the browser never triggers a new page load, nothing gets added to the browser history, and your analytics package has no idea who's doing what on your site.
Adding page loads to an SPA
You can add page load events to an SPA using HTML5 history API; this will hep you integrate analytics. The difficulty comes in managing this and ensuring that everything is being tracked accurately, which involves checking for missing reports and double entries.
The good news is that you don't have to build everything from the ground up. There are several open source analytics integrations for Angular available online, addressing most of the major analytics providers.
Is it a major problem?
The extent to which this is a problem depends on your need for undeniably accurate analytics. If you want to monitor trends in visitor flows and actions, then you're probably going to find it easy to integrate. The more detail and definite accuracy you need, the more work it is to develop and test. The more detail and definite accuracy you need, the more work it is to develop and test. While it's arguably much easier to just include your analytics code on every page of a server-generated sites, analytics integration isn't likely to be the sole reason that you choose a non-SPA route.
Speed of initial load
SPAs have a slower first page load than server-based applications. This is because the first load has to bring down the framework and the application code before rendering the required view as HTML in the browser. A server-based application just has to push out the required HTML to the browser, reducing the latency and download time.
Speeding up the page load
There are some ways of speeding up the initial load of an SPA, such as a heavy approach to caching and lazy-loading modules when you need them. But you'll never get away from the fact that it needs to download the framework, at least some of the application code, and will most likely hit an API for data before displaying something in the browser.
Should you care about speed?
The answer to whether you should care about the speed of the initial page load is, once again, "It depends." It depends on what you're building and how people are going to interact with it.
To SPA or not to SPA?
Just a reminder that this wasn't an exercise in SPA-bashing: we're just taking a moment to think about somethings that often get pushed to the side until it's too late. The there points about crawlability, analytics integration, and page load speed aren't designed to give clear-cut definitions about when to create an SPA and when to do something else. They're there to give a framework for consideration.
It might be the case that none of those things is an issue for your project, and that an SPA is definitely the right way to go. If you find the each point makes you pause and think, and it looks like you need to add in workarounds for all three, then an SPA probably isn't the way to go.
Designing a flexible MEAN architecture
We talked a little about what the technologies can do in chapter 1, but here are a few starting points:
- MongoDB can store and stream binary information.
- Node.js particular good for real-time connections using web sockets.
- Express is a web application framework with templating, routing, and session management built in.
Requirements for a blog engine
Let's take a look at the familiar idea of a blog engine, and see how you could best architecture the MEAN stack to build one.
A blog engine typically has two sides to it. There's a public-facing side serving up articles to readers, and hopefully being syndicated and shared across the internet. A blog engine will also have an administrator interface where blog owners log in to write new articles and manage their blogs. Figure 2.2 shows some of the key characteristics for these two sides.
Looking at the lists in figure 2.2 it's quite easy to see a high level of conflict between the characteristics of the two sides.
- You've got content-rich, low interaction for the blog articles, but a feature-rich, highly interactive environment for the admin interface.
- The blog articles should be quick to load to reduce bounce rates, whereas the admin area should be quick to respond to user input and actions.
Finally, users typically stay and a blog entry for a short time, but may share it with others, whereas the admin interface is very private and an individual user could be logged in for a long time.
Taking what we've discussed about potential issues with SPAs, and looking at the characteristics of blog entries, you'll see quite a lot of overlap. It's quite
A blog engine architecture
The answer lies in not looking for a one-size-fits-all solution. You effectively have two applications. You have public-facing content that should be delivered direct from the server and an iterative private admin interface that you want to build as an SPA.
Admin interface: an ANGULAR SPA
We've already discussed that this would be an ideal fit for an SPA built in Angular. So the architecture for this part of the engine will look very familiar: a REST API built with MongoDB, Express, and Node.js with an interactive private admin interface that you want t build as an SPA. Let's start by looking at each of the two applications separately, starting with the admin interface.
Blog entries: what to do?
Looking at the blog entries, things get a little more difficult.
So let's take another look at the MEAN stack, and think about all of the components. You know that Express is web application framework. You know that Express can use template engines to build HTML on the server. You know that Express can use Url routing and MVC patterns. You should start to think that perhaps Express has the answer!
Blog entries: making good use of Express
In this blog scenario, delivering the HTML and content directly from the server is exactly what you want to do. Express does the particular well, even offering a choice of template engines right from the get-go. The HTML content will require data from the database, so you'll use a REST API again for that.
This gives you an approach where you can use the MEAN stack, or part of it at least, to deliver database-driven content directly from the server to the browser. But it doesn't have to stop there. The MEAN stack is yet again more flexible.
Blog entries: using more of the stack
You're looking at an Express application delivering the blog content to the visitors. If you want visitors to be able to log in, perhaps to add comments to the articles, you need to track user sessions. You could use MongoDB with your Expresses application to do just this.
You might also have some dynamic data in the sidebar of your posts, such as related posts or a search box with type-ahead auto-completion. You could implement these in Angular. Remember, Angular isn't only for SPAs; it can also be used to add some rich data interactivity to an otherwise static page.
Now you have the possibility of a full MEAN application delivering content to visitors interacting with your REST API.
Blog engine: a hybrid architecture
At this point, there are two separate applications, each using a REST API. With a little bit of planning this can be a common REST API, used by both side of the application.
This is just a simple example to show how you can piece together the various parts of the MEAN stack into different architectures to answer the questions that you projects ask of you. You options are only limited by your understanding of the components and your creativity in putting them together. There's no one correct architecture for the MEAN stack.
Best practice: Building an internal API for a data layer
If you were to start off by building your application in Node.js and Express, serving HTML directly from the server, it would be really easy to talk to the database directly from the Node.js application code. With a short-term view this is the easy way. But with a long-term view becomes the difficult way, because it will tightly couple your data to your application code in a way that nothing else could use it.
The other option is to build your own API that can talk to the database directly and output the data you need. Your Node.js application can then talk with this API instead of directly with the database. Figure 2.7 shows a comparison of the two setups.
Looking at figure 2.7 you could well be wondering why you'd want to go to the effort of creating an API just to sit in between your application and your database.
You certainly don't want to find yourself in the position where you have to write separate but similar interfaces for each. If you've built your own API up front that outputs the data you need, you can avoid all of this. If you have an API in place, when you want to integrate the data layer into your application you can simply make it reference your API.
- It doesn't matter if your application is Node.js, Angular, or iOS.
- It doesn't have to be a public API that anyone can use, so long as you can access it.
As figure 2.8 shows, the previously simple integrated approach is now becoming fragmented and complex. You'll have three data integrations to manage and maintain, so any changes will have to be made in multiple places to retain consistency. If you have a single API, you don't have any of these worries. So with a little bit of extra work at the beginning, you can make life much easier for yourself further down the road.
Planning a real application
Planning the application at a high level
The first step is to think about what screens we'll need in our application.
Planning the screens
Dividing the screens into collections
Architecting the application
Because we're going to be transferring data from a database two a browser, letting users interact with the data and allowing data to be sent back to the database.
starting with the API
Because the application is going to be using a database and passing data around, we'll start building the architecture with the piece we're definitely going to need. Figure 2.10 shows the starting points a REST API built with Express and Node.js to enable interactions with the MongoDB database.
So the more interesting and difficult question is: How do we architect the application itself?
Application architecture options
At this point, we need to take a look at the specific requirements of our application and how we can put together the pieces of the MEAN stack to build the best solution. Do we need something special from MongoDB, Express, Angular, or Node.js that will swing the decision a certain way? Do we want HTML served directly from the server, or is an SPA the better option?
Thinking back to the blog example, we can immediately envisage three possible application architectures, as shown in the figure 2.11:
- A Node.js and Express application
- A Node.js and Express application with Angular additions for interactivity
- An Angular SPA
Wrapping everything in an Express project
The architecture diagrams we've been looking at so far imply that we'll have separate Express applications for the API and the application logic. This is perfectly possible and a good way to go for a large project. If we're expecting large amounts of traffic, we might even want our main application and our API on different servers. An additional benefit of this is that we can have more specific settings for each of the servers and applications that are best suited to the individual needs.
Another way is to keep things simple and contained and have everything inside a single Express project. With this approach, we have only one application not worry about hosing and deploying and one set of source code to manage.
When putting together an application in this way, it's important to organize our cod well so that the distinct parts of the application are kept separate. As well as making our code easier to maintain, it also makes it easier to split it out into separate projects further down the line if we decide that's the right route.
Breaking the development into stages
Rapid prototype development stages
Stage 1: build a static site
The first state is to build a static version of the application, which is essentially a number of HMTL screens. The aims of this stage are
- To quick figure out the layout
- To ensure that the user flow makes sense
At this point we're not concerned with a database of flashy effects on the user interface; all we want to do is create a working mockup of the main screen and journeys that user will take through the application.
Stage 2: design the data model and create the database
When we have a working static prototype that we're having with, the next thing to do is look at any hard-coded data in the static application and put it into a database. The aims of this stage are
- To define a data model that reflects the requirements of the application
- To create a database to work with the model.
The first part of this is define the data model. Stepping back to a bird's-eye view, what are the objects we need data about, how are the objects connected, and what data is held in them?
If we try to do this stage before building the static prototype, we're dealing with abstract concepts and ideas. When we have a prototype, we can see what is happing on different pages and what data is needed where. Suddenly this stage becomes much easier.
The first part of this is define the data model. Stepping back to a bird's-eye view, what are the objects we need data about, how are the objects connected, and aw
Stage 3: build our data API
After stages 1 and 2, we have a static site on one hand and a database on the other. This stage and the next take the natural steps of linking them together. The aim of stage 3 is
- To create a REST API that will allow our application to interact with the database.
Stage 4: Hook the database into the application
When we get to this stage, we have a static application and an API exposing an interface to our database. The aim of this stage is
- To get our application to talk to our API.
When this stage is complete, the application will look pretty much the same as it did before, but the data will be coming from the database. When it's done, we'll have a data-driven application!
Stage 5: Augment the application
This stage is all about embellishing the application with additional functionality.
So, really, the aims of this stage are
- To add finishing touches to our application
- To get the application ready for people to use
These five stages of development provide a great methodology for approaching a new build project.
No discussion about architecture would be complete without a section on hardware. You've seen how all of the software and code components can be put together, but what type of hardware do you need to run it all?
The good news is that you don't need anything particularly special to run a development stack. Just a single laptop, or even a virtual machine (VM), is enough to develop a MEAN application. All components of the stack can be installed on Windows, Mac OS X, and most Linux distributions.
If you have a local network and a number of different servers, you can run different parts of your application across them. For example, it's possible to have one machine as a database server, another for the REST API, and a third for the main application code itself. So long as the servers can talk to each other this isn't a problem.
The approach to production hardware architecture isn't all that different from development hardware. The main difference is the production hardware is normally higher spec, and is open to the internet to receive public requests.
It's quite possible to have all parts of your application hosted and running on the same server. You can see a basic diagram of this in figure 2.22.
This architecture is okey for applications with low traffic, but isn't generally advised as your application grows, because you don't want your application and database fighting over the same resources.
Growing up: a separate database serer
One of the first things to be moved onto a separate server is often the database. So now you have tow servers: one for the application code and one for the database. Figure 2.223 illustrate this approach:
This is quite a common model, particularly if you choose to use a platform as a service (PaaS) provider for your hosting.
Going for scale
Much like we talked about in the development hardware, you can have a different server for the different parts of your application — a database server, an API server, and an application server. This will allow you to deal with more traffic as the load is spread across three servers, as illustrated in figure 2..24.
But it doesn't stop there. If your traffic starts to overload your three servers, you can have multiple instances – or clusters – of these servers, as shown in figure 2.25.
Setting up this approach is a little more involved than the previous methods because you need to ensure that your database remains accurate, and that the load is balanced across the servers. Once again, Paps providers offer a convenient route into this type of architecture.