0

We develop a Single Page Application (SPA) for enterprise clients. When we deploy a new version of our SPA we would like to upgrade a subset of clients whilst leaving the other clients on the more stable previous version. After the new version become stable we then upgrade the rest of clients. The release cycle will always go on like this but each time we may choose a different subset of clients to try the new version.

I have thought this is a pretty standard release practice for enterprise application, call it beta-release or whatever. But to my surprise I can't much useful information about how to do it for SPA. I also face some technical difficulty, e.g. when a user sends the first GET request of the SPA (say, typing the url of the SPA in the browsers) how do I send him the correct version? It involves DB query to find out the correct version for him, but how to do that in the http request/response cycle ?

I search softwareengineering, find this Why make the login page to a single page application a separate page? It is actually what I am thinking now, e.g. make the login part a standalone app apart from the rest of my SPA. So in the login process I can decide which version I should show to this user and redirect him that version.

But is there other way to achieve what I need ? I think it involves an overall design/overhaul to my current SPA architecture.

--- Update ---

I only allow a client to use one version I assign to him. A client can't use both versions. So if I design to add v1/v2 in the URL and he types the wrong version for him I will redirect him to the correct version. But I have not decided whether to add version number to URL path. This is another design choice to make.

--- Update 2 ---

A version specific url is one of tricky parts I have not thought through even after reading joshp's answer. I make some simplification for my cases before I list my question. We use subdomain to designate tenants in our multi-tenant web application, as explain here Why use subdomains to designate tenants in a multi-tenant web application? and use a wildcard DNS record to map any tenant url to the main 'front-door' url. We don't allow a tenant to use both version, either the latest or the old one.

To add version info to url, then tenant1.mydomain.com will map to the latest version of mydomain.com, e.g. mydomain.com/v2, tenant1.mydomain.com/v2 also maps to the latest version mydomain.com/v2 and tenant1.mydomain.com/v1 maps to mydomain.com/v1

Here are 2 scenarios what I don't know how the server, especially the reserve proxy handle it properly. It is not a fixed rule that a tenant will always use the old version (or the latest version). It may change for each new version. If it is a fixed rule my problem will much simpler! That is the main reason I want to introduce a standalone login app.

  1. Since the url without the version will map to the latest version, if tenant1 should use the old version this time while he always type the url without version number, how does the reserve proxy handle it programmatically.

  2. if tenant1 should use the latest version while he type tenant1.mydomain.com/v1 how does the reserve proxy handle it ?

In both the reserve proxy (nginx) can't just simple do URL rewrite because whether a tenant will use the latest version may change.

15
  • It somewhat depends on how this versioning works. Are you allowing users to use both versions if they want, or are they forced to use the one you've assigned them?
    – Flater
    Jul 8, 2021 at 9:17
  • Just one version I assign them Jul 8, 2021 at 9:19
  • @Flater I updated my question. I have not decided whether to add version number in the url yet. This is actually another design consideration. Jul 8, 2021 at 9:25
  • Is the backend API also versioned according to these SPA versions, or do the two SPA versions use the exact same API?
    – Flater
    Jul 8, 2021 at 10:08
  • 1
    Why is this being down voted?
    – Blake
    Jul 8, 2021 at 12:10

1 Answer 1

1

There are a lot of ways to do it, depending on your requirements.

I do this by returning the UI URL from the login request as follows...

  1. User navigates to the app in the browser.

  2. App's current version is retrieved (possibly from cache) and loaded.

  3. Login page is presented because user is not logged in.

    • This means all users who visit our service without a prior session or ui-version specific url get the current app version's login view.
  4. User provides credentials. App sends an http request to log in.

  5. If user is authenticated and authorized to log in, service sends a 200 response with a JSON body containing the url to proceed into the correct version of the app. The server decides which version based on information it has about our customers.

    • If the url is for the current app version, the browser does not navigate to a new page. Only info after the hashtag changes. The app handles the routing.

    • If the url is for an older app version, the browser navigates to a new page, loading the old version from scratch.

  6. User continues in the appropriate app version.

Special Cases (not so special really)

  1. User navigates to a version specific url instead of the main 'front-door' url.

    • If the user is not logged in and the older version url is still supported, the older app version will allow the user to log in and then navigate to the correct version.

    • If the older version is not supported, user will get a 404. We hope they will try our main url. And if we get a support question we'll say, hey our url is blah.com use that please. In practice we get no real trouble from this.

    • If the user is already logged in to an older supported version, they can continue their session. We're not going to check whether they would get a newer UI next time they log in. Just let them proceed and get newer UI next time they log in.

  2. Software upgrade occurs while users are logged in (doesn't it always?)

    • As long as we still support the old version they are using, they can continue in their session. Next time they log in they might get a newer UI.

    • If we don't support the old version they are using they will start getting errors next time they try to retrieve a UI component. This will be ugly. This is why we generally don't drop support for old UI until a couple of days after all users have switched to a newer version.

    • If old unsupported UI is fully downloaded and cached they might hit breaking api changes that were allowed since we dropped support for the old UI. It could be annoying or do a lot of damage. We wait for old IU support to drop before making such breaking changes, which are extremely rare anyway, and usually take the form of eventually removing deprecated methods.

  3. What if we need to make a breaking change to the login process?

    • We'll cross that bridge when we come to it. The process is so simple it's unlikely to happen.

Downsides

  • Supporting old versions is expensive. Lots to think about and more testing to do. In our case it's necessary.

  • Users directed to the old UI from the current login view wait for the app to load twice. This may or may not be a problem depending how your app downloads and loads static resources and how long that takes to just get to the login view. For us it's a non-issue.

Otherwise this has worked pretty painlessly for years. We also do it with iOS native/hybrid apps where the info retrieved from the login request drives feature flags in the native app in addition to driving which static resources are used for HTML/JS in WkWebView.

Alternatives

You could separate the login UI from the rest of the app and always redirect from the login.

One reason we don't do this is that if the user's access token expires we want them to be able to re-authenticate. If we navigated to a login page outside the app, the app state would be lost. When we want to lose that state we can force a reload. One such case is when the new login is a different user. But usually we don't want to lose it.

Let's not talk about quirky stuff like using iframes to log in.

It appears a fair number of enterprise apps do separate login from the main app, and you can see this when your session expires and you get a different login page or have to start the app over from scratch. Those are reasonable choices for some apps.

2
  • Thanks for the detailed summary. One of difficulties of my problem is to think thought all the scenarios and weigh the pros and cons of different solutions before I choose one. Jul 9, 2021 at 1:48
  • Hi I updated my question to list the main reason why I am thinking about adding a standalone login because it is not a fixed rule that some client will always use the old version. Can you take a look. How do you handle it ? Jul 9, 2021 at 3:54

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.