Sponsor: Do you build complex software systems? See how NServiceBus makes it easier to design, build, and manage software systems that use message queues to achieve loose coupling. Get started for free.
How can you build a smarter Single Page Application with a REST API? The concepts have been since the beginning of the web, yet have somehow lost their way in modern REST API that drives a Single Page Application or Mobile Applications. Here’s how to guide clients based on state by moving more information from design time to runtime.
Check out my YouTube channel where I post all kinds of content that accompanies my posts including this video showing everything that is in this post.
If you’re developing more than a CRUD application, you’re likely going to be driven by the state of the system. Apps that have Task Based UIs (hint: go read my post on Decomposing CRUD to Task Based UIs) are guiding users down a path of actions they can perform based on the state of the system.
The example throughout this post is the concept of a Product in a warehouse. If we have a tasks that let’s someone mark a Product as no longer being available for sale or it being available for sale, these tasks can be driven by the state of the Product.
If the given UI task is “Mark as Available” then the Product must be currently unavailable and we have a quantity on hand that’s greater than zero.
History of Clients
Taking a step back a bit, web apps were developed initially with just plain HTML (over 20 years ago for me). In its most basic form, a static HTML page contained a <form> that the browser rendered for the user to fill out and submit. The form’s action would point to a URI usually to a script, often written in Perl, in the cgi-bin folder on the webserver. The script would take the form data (sent via POST from the browser) and insert it into a database, send an email, or whatever the required behavior was.
As web apps progressed, instead of the HTML being in a static file, it was dynamically created by the server. But it was still just plain HTML.
The browser was the client. HTML was the content it’s consuming.
Runtime vs Design Time
When the Browser is the client consuming HTML, it understands how to render HTML. HTML has a specification. The browser understands how to handle a <form> tag or a <button>. It was driven by the HTML at runtime.
This is a shift from runtime to design time in modern clients.
When developing a SPA, you may leverage something like OpenAPI to generate code to use in the SPA/clients to make the HTTP calls to the server. But you must understand as a developer, at design time (when developing) when to make a call to the server.
To use my earlier example of making a product available for sale, if you were developing a server-side rendered HTML web app, you wouldn’t return the form apart of the HTML if the product couldn’t be made available. You would do this because on the server you have the state of the product (fetched from the database). If you’re creating a SPA, you’re likely putting that same logic in your client so you can conditionally show UI elements. It wouldn’t be a great experience for the user to be able to perform an action, then see an error message because the server/api threw a 400 because the product is not in a state to allow it to be available.
Hypermedia is what is used in HTML to tell the Browser what it can do. As I mentioned earlier, a <form> is a hypermedia control.
When a user clicks the submit button, the browser is going to send a POST request to /mvc/save?Sku=123
The HTML is telling the Client (Browser) that his action is available.
Another hypermedia control is the <a> tag that is when clicked by the user in the browser, will then making an HTTP call to /mvc/images?Sku=abc123 and then render the returned HTML.
The HTML is telling the Client (Browser) where else it can navigate to.
The server is serving HTML that is providing the client with this information at runtime.
The vast majority of modern HTTP APIs serving JSON, do not provide any information in the content (JSON) about what actions or other resources the consuming client (SPA) can take. Meaning, we provide no information at runtime. All of that has to be figured out at design time.
In the example of a product, your typical response might look like this:
But how does your SPA know if it can mark the product as available for sale? Again, this is based on the state of the product, which your server knows since its returning you the state.
We can take the same concepts as forms and links and apply them to our modern HTTP APIs.
Now we’ve provided information at runtime to the client. If our client is developed at design time to know these links/actions may or may not exist, it can develop the appropriate UI to either show or hide certain functionality.
Now instead of being 100% design time, we’ve shifted more towards runtime.
You will still need to know (via OpenAPI) at design time, all the information about the routes you will be calling, and their results, however, you can now have the server return JSON that can guide the client based on state.
This isn’t a new idea at all. Hypermedia in HTTP APIs exists with defined media types. Check out:
Developer-level members of my CodeOpinion YouTube channel get access to the full source for the working demo application available in a git repo. Check out the membership for more info.