matiso
Phoenix >= 1.3 umbrella architecture
Today I watched @chrismccord’s talk about the changes coming to Phoenix starting with version 1.3 and I really, really love the direction that Phoenix is going.
I have worked with both monoliths and microservices, and both have their known pros and cons. Phoenix Umbrella seems to be going in the right direction of providing best of both worlds: a strongly modular system, without the overhead of separate deployment.
One thing that I like about the --umbrella flag is that it completely separates the business layer from the web / presentation. But here I’d like to go even further. I would love to see an even more radical separation. Let me explain.
I have a web application that you can think of as a SaaS offering. It has a front page, pricing page, a login / signup form. After logging in, you get to see a dashboard that is a JS-app that communicates with a JSON/REST api. The REST API is the only source of data for the application and is both used by customers and the application itself.
Having this, I have created a Phoenix umbrella application structured the following way:
apps/my_app → the business logic layer (encapsulates and abstracts the communication with the db)
apps/my_app_web → the presentation layer for the HTML stuff
apps/my_app_api → the API business logic layer (mostly communicates with my_app, exposes the models)
apps/my_app_api_web → the API presentation layer for the JSON stuff
So the dependency tree looks like this:
my_app ← my_app_web (renders the assets)
my_app ← my_app_api ← my_app_api_web (exposes the REST api)
my_app_api ← my_app_web (uses the REST api)
The only way to achieve this structure was by creating the my_app umbrella project first, then the my_app_api umbrella second, and moving both my_app_api and my_app_api_web under the /apps folder of the my_app umbrella. I had to change the port of my_app_api_web to not collide with my_app_web. Not very clean, but hey, it works!
I’d love to see Phoenix evolving into a framework that naturally supports this kind of separation of concerns. Going further, I’d like to allow to have multiple “web” layers (e.g. public front-page vs application for logged in users, api, etc). This way the routers always stay clean and focused. The system naturally avoids growing into a bloated monolith.
Having a separate application for the API exposers might sound like an overkill, but I want to keep the business logic concerned with abstracting the DB in a clean way, and have the API layer be built on top of it. As an example, I have a lot of Swagger definitions in the API application, which I think does not strictly belong to the business logic.
Thanks again for making it possible, I’ve been waiting for this for so long!
Most Liked
chrismccord
Phoenix 1.3 also includes two new project generators for running inside an umbrella’s apps/ directory: mix phx.new.web and mix phx.new.ecto. So in your example, you could use the --umbrella flag, then generate your api, api_web, and other apps with these two generates. I think we already support what you suggested
Glad you like the direction!
Gazler
@iampeterbanjo Pretty sure you need some additional settings for WebSockets and nignx (taken from NGINX | F5):
proxy_pass http://127.0.0.1:4010;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "Upgrade";
Nginx is the way I would go for hosting multiple applications on the same server.
matiso
Last Post!
maz
This may not be specifically applicable to this thread but if anyone is looking for an alternative to nginx as a proxy, we have successfully set up Traefik as a proxy to a phoenix 1.4 app.
Traefik will manage letsencrypt renewals and can detect internal resource changes without a restart.
Popular in Questions
Other popular topics
Categories:
Sub Categories:
Forums
Popular Tags
- #ecto
- #liveview
- #troubleshooting
- #learning-elixir
- #deployment
- #library
- #erlang
- #testing
- #genserver
- #mix
- #absinthe
- #remote-other
- #otp
- #plug
- #how-to-question
- #macros
- #postgres
- #channels
- #elixirconf
- #exunit
- #discussion
- #code-sync
- #javascript
- #podcasts
- #onsite
- #dialyzer
- #docker
- #authentication
- #umbrella
- #full-time-contract
- #podcasts-by-brainlid
- #ecto-query
- #elixir-ls
- #phoenix_html
- #iex
- #blog-post
- #graphql
- #genstage
- #ai
- #websockets
- #supervisor
- #elixirconf-us
- #advent-of-code
- #distillery
- #processes
- #api
- #forms
- #metaprogramming
- #security
- #hex










