Open kakawait opened 7 years ago
As @kakawait said, this is kind of scratching an itch I have at the minute, encountered while trying to build a demo for Spring Cloud Function. Serverless and functions mean the backend services get smaller and more numerous, so the pain is likely to be greater if anything. But a traditional microservice architecture clearly has the same tensions (the Xebia blog is quite good at describing the problem, if not really the solution).
I think there are a range of options, not all of which are as heavy architecturally as the existing tools in the node.js world referenced above (hence, for example, my question about whether you really needed a gateway and a layout service to be distinct physically). I also think the "component service" is a possible source of over-engineering complexity. It probably depends on your needs and the tools you use for the actual UI implementation.
I'm not really an expert on the UI side, so shadow DOM, react components, etc. are in my lexicon, but I can't really comment on the detail. IMO we would need a real UI expert to guide any concrete efforts here, and provide options that don't restrict the choices of front or back end technology (it's simply too diverse in the UI world for us to bet on any individual horses).
We would also need to keep a rein on anything that started to look too opinionated or too grandiose.
I have made some prototypes (sample apps) that demonstrate how you can use various different mechanisms to pull content through from a backend service.
It's super easy to set up a proxy in the gateway to mirror back end resources based on a naming convention. You could use Zuul, or spring-cloud-gateway, or just hand code an MVC endpoint (Spring 5 has a new ParsingPathMatcher that makes it a bit easier). You could use service discovery, or just configuration. I don't think we need to be prescriptive. The samples just do it in MVC with config for the backend URLs.
AngularJS has an ng-include
directive which works really smoothly. All you need is for the gateway to proxy the fragment resources (to prevent issues with trust in the browser). I assume other front end frameworks can do the same thing.
If you need server side templating as well (probably a good idea for the general case, but maybe not all apps), Spring Boot makes it easy to customize the template libraries to load templates from a custom source. Again you can use a naming convention and a proxy pattern to pull them from the backends. I tried it with Thymeleaf and Mustache and it was only a few lines of code for each in the gateway.
Sample code here: https://github.com/dsyer/frontend-microservices. Also see the Petflix sample (Thymeleaf template fragments from the backend): https://github.com/dsyer/petflix. That one is interesting because it is a real legacy monolith (Petclinic) with a new feature added as a microservice (pet videos).
Yes I omitted something that @dsyer highlight, above solution is a solution among many others. Is not better or worse than other is just depending on your needs.
Some are using BFF (Backend For Frontend) like Netflix which is completely understandable since Netflix are working with many (more than 99% peoples) devices from pc to phone to gaming console and other.
As @dsyer said transclusion as I proposed can be done using CSI (Client Side Inclusion) like ng-include
or ESI (Edge Side Inclusion).
Finally as same @dsyer
I'm not really an expert on the UI side, so shadow DOM, react components, etc. are in my lexicon, but I can't really comment on the detail. IMO we would need a real UI expert to guide any concrete efforts here, and provide options that don't restrict the choices of front or back end technology
I'm not even an expert on the UI side too.
Updated: I said some stuff about Tailor, deleted.
Tailor is just a revisite of BigPipe from Facebook (Facebook still using BigPipe, I let you check page source code to confirm). The main problem that BigPipe (and Tailor) resolve is
When the web server is busy generating a page, the browser is idle and wasting its cycles doing nothing. When web server finishes generating the page and sends it to the browser, the browser becomes the performance bottleneck and the web server cannot help any more.
See https://www.oreilly.com/ideas/better-streaming-layouts-for-frontend-microservices-with-tailor and https://www.facebook.com/notes/facebook-engineering/bigpipe-pipelining-web-pages-for-high-performance/389414033919/
@dsyer We just checkout and look more about your sample https://github.com/dsyer/frontend-microservices. Is really impressive and I think we will start with the Thymeleaf version, is exactly what we are looking. Only thing I have to check is if UrlTemplateResolver
can be parallel.
I will continue working on BigPipe version (using Spring 5) for my personal challenge and maybe futur optimization.
I think I can close issue since is not directly related to spring cloud gateway. I think I will check with Thymeleaf project and new reactive support to maybe be extended to support that use case.
Keeping this on our radar, especially with the spring reactive story.
@spencergibb no problem, I will happy to help you guys on that subject. I just would add a point to do not forget when trying to stream UI is SEO.
I know is possible to stream UI using SSE and Thymeleaf (https://github.com/thymeleaf/thymeleafsandbox-sse-webflux) but I don't really know how Google is able to index something that is generated with Javascript and SSE.
I'll try to get some research about SEO, since I'm totally not an expert.
Here's another video that I found really useful (how to do it in Play from LinkedIn):
https://www.youtube.com/watch?v=4b1XLka0UIw
And a SPR JIRA issue:
https://jira.spring.io/browse/SPR-14981
Thymeleaf has a few features, but they are kind of limited at this point in time. It can flush HTML in a smart way if there is a single model attribute of a specific type (they call it a "driver" for the flushing). I believe you could do better. The SSE model is a bit different (it is driven by the same mechanism in Thymeleaf), but it is also limiting, I think, because it requires a separate HTTP connection per stream, and because it requires a lot of boilerplate on the client.
First at all that project seems really promising, far better then
Zuul 1
version!Last day I was talking with @dsyer about designing/prototyping a kind of layout service / ui composition service (whatever the name) inspired from Zalando
Tailor
project (from global Mosaic project - Microservices for the Frontend).Goal of such service is to avoid getting a well designed and decoupled backend service used by a big monster monolith (SPA?) frontend. Each microservices could be responsible on their own frontend/ui fragments, layout service / ui composition service will be only responsible to aggregate every fragments using a base/master template and returns it.
I wanted to develop by myself a kind of closely inspired fork to Zalando
Tailor
but using Java + Spring 5 + Spring Boot 2.0 + Reactor. Though I really need such piece of service on my current stack, at start that project was also a good candidate for training myself to Spring 5 + Spring Boot 2.0 + Reactor.When I spoke that to @dsyer I also proposed an possible architecture based on Zalando one
And mine (Yes is a totally a clone of Zalando one :trollface: )(Attention is a prototype, any box is not necessary a dedicated services. Is more a logical view)
At this point, @dsyer ask me why I have separated gateway and layout service. I don't really have a clear answer but in my mind, only reasons was separation of concerns and resilience (if layout service get down, you can continue using
API
). But I didn't think more.That why I open you an issue (is more a discussion, I'm not asking feature request) to
Existing alternative or similar project to Zalando
Tailor
Here some sources of inspirations about Microservices for Frontend topic: