API + SPA Deployment Best Practices
Asked Answered
N

3

7

Developing a SPA in the frontend (with Vue.js) which consumes endpoints from a (Laravel) API in the backend introduces some challenges that need to be tackled:

1. How to sync deployment when introducing new backend/frontend code

If the code is separated in two VCS repositories (frontend/backend) it can be challenging to sync deployment of both frontend and backend making sure that both finish at the exact same time. Otherwise this can lead to unexpected behaviour (e.g. calling endpoints that are not yet deployed or have changed). Anyone came up with a great solution for this? What is your best practice to tackle this problem? What if versioning every little change is not an option?

2. How to make sure that the frontend code of the SPA is being refreshed after deployment?

So you managed to keep your deployments in sync (see problem 1.), but how do you make sure that the SPA code of every currently active end user is being refreshed? With webpack code splitting enabled, the application might break immediately for users that are currently using your app in between a deployment.

How do you make sure that your users are being served the latest JS without having them reload the entire application on every request? What are best practices (besides forcing the user to refresh the entire page via websockets)? Are there solutions that allow currently active users to keep using the application without being forced to refresh while they might just finished something that's ready to be saved?

I am very interested in your findings, learnings and solutions!

Necroscopy answered 21/7, 2017 at 7:22 Comment(1)
You may take a look at quasar.dev (open source and free). After a long look for this myself this seems very promising. The condition is that the framework is used from day 1. There is a Vue CLI possibility and even stand alone, but integrating the SPA in a Google/Apple app becomes more complex. If you are not interested in converting an SPA to an app, Quasar may not be the best solution.Rosalindarosalinde
S
7

1. How to sync deployment when introducing new backend/frontend code

The best practice here is to keep the backend and frontend in the same repo. You can, of course, extract some reusable code out of them to use in other projects but the code base should ideally be in the same repo or you will keep facing these frustrating code sync issues. Even if you look at popular Laravel libraries - they all have the frontend and backend in the same repo.

If that's not option, I would suggest that you use a versioning system that can link the versions of both repos. Yep, that means versioning every little change!

2. How to make sure that the frontend code of the SPA is being refreshed after deployment?

Usually, I'd avoid doing stuff to force a refresh on the client codebase but if you have long user sessions, it may actually make sense.

To do that, you can use any web socket implementation (such as Pusher) and have your CI notify the frontend through web sockets of any deployment. The frontend can then queue a page refresh. Check out this article on how to implement.

Simultaneous answered 23/6, 2019 at 6:27 Comment(7)
Not sure how putting everything in one repo would help here. You still have to run both test suites on a staging env to ensure that everything works. What do you do if you decide to add a desktop client, for example? I think the best practice is to use separate repos because it scales better. Especially once you have different people working on API, SPA, mobile, ... which is common, then separate repos allow for greater flexibility and help avoid conflict between the teams.Tricky
Making sure versions match is a nightmare with separate repos. If different people are working on SPA, mobile, etc., you should have separate repos for each. But the backend and frontend of SPA, backend and frontend of mobile, etc. should each be on the same repo. That scales better rather than having all backend on one repo and all frontend on another. There will be no conflicts this way and much more flexibilitySimultaneous
So you copy/paste your API for each client? Do you have separate DBs as well?Tricky
No, you extract common code in a separate repo and pull them into the various repos for mobile, SPA, etc. Of course, you have a shared DBSimultaneous
Ask yourself a simple question. Which parts of the code need to be in sync? Does the mobile code need to be in sync with the SPA code? Maybe a small percentage which can be extracted to a separate repo. Does the mobile backend need to be in sync with the mobile frontend? Absolutely 100%! That's why they should be in the same repoSimultaneous
Maybe I'm missing something. How exactly does it help to have a copy of your API in each client repo? Mobile is separate from SPA and API is separate from both. Before a new release you test everything. No?Tricky
If your API is common for both, extract it in a single repo (added flexibility to override). If not, then write separate codebases in separate repos. Quite often, mobile app and SPA would have a different set of APIs. But never ever would your mobile app backend not be in sync with your mobile app frontend and so on. You mention tests but tests are never foolproof. It's impossible to test everything with integration tests. It's much better to have a single repo for interdependent code than to just rely on test coverage.Simultaneous
F
5

The two questions are tightly coupled and can't be answered separately in my opinion. I have some possibile strategies to deal with such a scenario:

1. Never introduce breaking changes in the API

API deployments should be incremental without breaking anything for users using the previous version. In this way you can simply push the changes on your backend and when the backend deployment is completed you deploy the frontend. Easily achieved if you have separate projects. This can be performed for major releases by prefixing the API with the version:

https://website.url/api/v${version}/${endpoint}

while minor deployments should only be minor adjustments/bugfixes that do not break frontend functionality.

This approach is the best because it ensures absolutely no downtime in the user activity, but requires additional work and may not be feasible in many projects. If the backend does not introduce breaking changes, you can implement a simple polling system (with a long timespan, such as minutes) from the frontend that detects if a reload in necessary to load the new frontend deployment.

2. Standard response for outdated requests

  • Each request from the frontend includes an information about the version in use by the frontend. It could be a standard header, a param, whatever. You should wrap your requests in a function that add the information before sending the request itself.

  • If the server detects a request from an outdated frontend, it returns a standard response, such as:

{
    "error": "update required"
}
  • The frontend detects the error and reload the page

I honestly don't like this approach, because the request may be a POST request with some form data and a page reload may lose the user all their input, which is annoying.

Furness answered 26/6, 2019 at 15:47 Comment(0)
T
0

1. How to sync deployment when introducing new backend/frontend code

With a staging environment where you run both test suites before pulling on production.

2. How to make sure that the frontend code of the SPA is being refreshed after deployment?

Don't just break your API. Implement a grace period. For example, you could check for updates on every request, then notify the user that a new version is available so that they have to click a button at their earliest convenience. Record the used client version in your DB. Once all your users are updated, you can delete the old endpoints.

Tricky answered 24/6, 2019 at 14:43 Comment(8)
Question isn't about how to run test suites. It's about how to make sure backend and frontend code are in sync always. Even the second question isn't addressed. The OP doesn't want the user to click a button and refresh. What is needed is how to update code without a refreshSimultaneous
Well, how do you make sure that they are in sync? By running tests. The OP doesn't want to refresh on every request, not never. Also, OP doesn't want to force the user to update. That means giving control to the user. That's also what Todoist does, for example.Tricky
Ahh I see what you mean. Makes sense if you have integration tests included in your test suites. Many folks just do unit and feature tests while skipping integration, in which case that won't work.Simultaneous
Also you would still need a common versioning system to know which versions of the 2 repos to pull before running the testsSimultaneous
Agreed! Integration tests are vital. You pull the latest version on the staging branch from all repos before testing.Tricky
The latest branch is never the worry. It's when we need a revert to an older commit when hell breaks lose - that's where syncing 2 repos becomes a big challengeSimultaneous
That's very true. That would mean you run multiple instances of your API for each client in order to be able to revert?Tricky
Yes running multiple instances would make sure that stuff on the client side doesn't break but we also need to make sure we can map older commits between backend and frontend code repos if they're separate repos. Maybe a common versioning / tagging systemSimultaneous

© 2022 - 2024 — McMap. All rights reserved.