When to request data in SPA
Tags: spa, webdev, client, request
Published: 2020-07-04 15:45:44

I came to [SPA (single-page application)](https://en.wikipedia.org/wiki/Single-page_application) development from MPA (multi-page application). Surprise, surprise, they are not identical. SPA has some unique concepts, that you don't need to think about in MPA. One of them is the issue with requesting data from API. In MPA development, every user interaction is a new request to server and every URL, you put in the browser, is also a new request. But SPA has much more options. You can request some data at the start of your application, then there are moments (usually preceded with user interaction) when you have to request other data for you application.

My understanding is that every application state should be represented by a URL (and vice versa, every URL should be able to provide correct content), no matter if you are building SPA or MPA. For example, if I had an application that allowed you to list books and view a detail of a book, I would probably have 2 kinds of URL:

* /books
* /books/:id

However, when I am building SPA it's not that obvious, when is the right time to request data from API and when to change URL. It seems to be all one atomic action in MAP (user interaction, URL change, request), but in SPA you have to choose what is the right sequence. I used Angular and Vue for my projects, but I cannot remember that I read about this in their documentation. They give you many tools, but they don't mention what is the correct tool for managing asynchronous data for your views.

## API request first

> user interaction -> API request -> change URL -> change view

I thought, that most API requests should start with some user interaction (for example clicking a button). This idea was much easier to comprehend for me. User sees list of books, they click on a book and app will request a detailed information of this book and if this request is successful app will change the URL (and view) to the book detail. Then I noticed some other advantages. Your views don't have to handle an invalid state, when they don't have data, because app will change URL only if data is correct. This can reduce your _if_ statements in the view. But this approach is failing, if user just enters URL into the browser. This will be a special case, that will haunt you during entire development process. It was such a big issue for me, that I tried to think of an other way to request data from API.

## URL change first

> user interaction [optional] -> change URL -> change view -> API request

I had to get rid of my assumption, that API request should follow user interaction. Instead, I made my special case my main use case. I have to be able to serve correct content to user if they enter URL to browser. In other words, I want to make a URL change to trigger API request. Angular is equiped with [guards](https://angular.io/guide/router#milestone-5-route-guards) and [resolvers](https://angular.io/guide/router#resolve-pre-fetching-component-data) and vue is equiped with [guards](https://router.vuejs.org/guide/advanced/navigation-guards.html) and [component lifecycle](https://vuejs.org/v2/guide/instance.html#Instance-Lifecycle-Hooks). You will probably have to make your views more robust (you will have to handle invalid data, because API request will be asynchronous and view will be already rendered) but I found it a small price for easier data requesting. And let's be honest, you would probably want to handle invalid data in view anyway.

Of course, you are still able to react to user input. When user clicks on a button, you will change URL and everything will continue as if user only inserted URL to browser.

> Note: Router can behave differently in each framework. For example Vue won't notify you if there is a change in URL parameter. This can be handled by watching URL parameter, but I found it a little bit odd. There is probably some good reason behind this design decision, but I'm yet to find that out.

I find the second approach, URL change first, much easeir to work with. I still strugle with some concepts, but I think it might take me some time to get used to them. Or maybe there is still something I am missing.