Sunday, October 16, 2016

Spring Boot error pages, angular ui-router, and grunt integration

Spring Boot has a useful feature for providing a global error page based by status code by placing an html file named with the status code in your static resources.
http://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#boot-features-error-handling-custom-error-pages

One of the problems with this however, is if you want to maintain a separate javascript build for your webclient and are using angular and ui-router as a single page webapp, maintaining your sources will become a pain.  For instance, if you want menus to continue to work, how are you going to accurately change the state when a 404 page's location is to "/non/existent/weird/path".  Without using a template rendering library on the server side, this becomes a problem.

There are a lot of ways this could be handled, you could jump through a lot of hoops rewriting all your urls.  You could utilize Spring ResourceTransformers.  You could ensure *everything* for headers/footers/and the like are all pulled in as templates (or god forbid copy them and maintain them in two different locations).

Because the project I'm working on already utilized the processhtml grunt plugin, I decided to just add additional targets for each of my error pages.

First, add the targets to your grunt configuration:
It goes without saying to adjust your build output accordingly, just ensure that the error directory ends up in a Spring Boot recognized static resource location.

Now, let's do some templating within our index.html file like so:
What we are doing is removing the ui-view div for our main app here when we are building an error page, but pulling in content for our various error statuses.

This gets us most of the way there.  But what if your app is served under a sub directory?  What if the 404 is on some nested path.

I tend to dislike using base hrefs (just an opinion), but we can leverage one here.  Add the following to the head of your index.html source:
And the following in your base.html fragment:
Now we will force all links to images/js/css/etc to go back to our main app.

What is the meta tag for?  Well, that is just something I placed in that can be detected during state change for ui-router.  I added the following to my angular app to force changing the window location when a submenu is clicked in my menu bar:
This is kind of a dirty hack.  But now we can maintain our entire app within one source file.  I think this is good enough.