matiso
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!
Trending in Questions
Other Trending Topics
Categories:
Sub Categories:
Forums
Popular Tags
- #ecto
- #liveview
- #troubleshooting
- #learning-elixir
- #library
- #deployment
- #erlang
- #testing
- #genserver
- #mix
- #absinthe
- #remote-other
- #otp
- #plug
- #how-to-question
- #macros
- #postgres
- #elixirconf
- #channels
- #exunit
- #discussion
- #code-sync
- #podcasts
- #javascript
- #onsite
- #dialyzer
- #docker
- #authentication
- #umbrella
- #full-time-contract
- #podcasts-by-brainlid
- #ecto-query
- #elixirconf-us
- #blog-post
- #elixir-ls
- #ai
- #phoenix_html
- #iex
- #graphql
- #genstage
- #websockets
- #supervisor
- #advent-of-code
- #distillery
- #processes
- #api
- #forms
- #hex
- #security
- #metaprogramming










Showing Posts 1 to 10- Show Best Posts
- Show All (oldest first)
- Show All (newest first)
chrismccord
Phoenix 1.3 also includes two new project generators for running inside an umbrella’s
Glad you like the direction!
apps/directory:mix phx.new.webandmix phx.new.ecto. So in your example, you could use the--umbrellaflag, then generate your api, api_web, and other apps with these two generates. I think we already support what you suggestedmatiso
Wow, this is great stuff! Keep up the good job
und0ck3d
@chrismccord is it possible to run, let’s say “app_web” and “app_api” in the same port? Perhaps using a proxy? How can one achieve this, any example?
Thanks in advance.
und0ck3d
I stumbled on this github repo which has an example of what I’m trying to achieve, using the
master_proxyapp.Is that example suitable for development? I mean will it have any negative impact, such as loss of live reloading or anything else?
Because I’d have to run it like: (right?)
Thanks once more!
Gazler
I wrote the
master_proxyapplication originally to solve an issue with running an umbrella application on Heroku, where only one port is available.What you have suggested would work, however I find it much easier to run
mix phoenix.serverfrom the route of the umbrella and have both applications running on different ports. So I can go to http://localhost:4000 for the API, and http://localhost:5000 for the web application.und0ck3d
Thanks for the quick answer @Gazler!
In that case, to separate web and API, I think you’re right, and it’s more practical as it will probably run in a sub-domain (each app proxied by NGINX).
But imagine I have, let’s say, the web (application per se) and admin, which I’d like to separate in code, but to run on same port.
I’ve achieved this behavior by creating a
mix phx.new myapp_admin --module MyApp.Adminapplication in/appsdirectory, removing themodparam fromapplicationsfunction inmyapp_admin/mix.exs, adding this as a dependency ofmyapp_weband thenforward "/admin" MyApp.Admin.Router.However with this “solution” I’ve lost live reloading for the
myapp_admincode and assets compilation…Three questions, if you don’t mind:
Thank you in advance!
und0ck3d
Well, I was able to make live reloading and assets compilation work again for the
myapp_adminapp, buy updating the following files in themyapp_webapp:File:
myapp_web/config/dev.exsFile:
myapp_web/lib/myapp_web/endpoint.exOfc, this doesn’t look like a very elegant solution, but it works!!
I was wondering if there’s another way to work this out or improve this solution… Any ideas?
Thank you very much!
Gazler
I can see why you would want them running on the same port in production (with some sort of proxy in front of them). I’m not sure why you would want to do it in development. If there is some reason that they need to exist together then they may not be good candidates for separating into different apps.
You an always run them both on separate ports to allow you to run
mix phoenix.serverfrom the root for the code reloading. Then you canforwardas you have done already and just ignore the fact that the admin section is running on a different port. This means that you don’t need a work around like you have, but you can also run both applications in isolation.If you look at the Phoenix supervisor, you will see that both the
watcher_children(for code reloading) andserver_childrenworkers use the sameserver?/1function to see if they should be started phoenix/lib/phoenix/endpoint/supervisor.ex at 4ff5a3e21ed8e1ca892e3bb60d3511d4cf8a2a1b · phoenixframework/phoenix · GitHubund0ck3d
All of this comes from the will to separate code as much as possible so that I don’t end up with a monolithic application. That’s why I want backoffice and frontoffice code to live in two separate “apps” or “directories”, as I would if I was to add an API to this project as well.
I now see that it really doesn’t matter if apps are running on different ports as long as I
forwardthe app-sepcific path to correspondent router. I believe that approach will work well instead of the messy workaround I previously had in place.However, when using that approach, as I’m calling the
App.Backoffice.Routerinstead of calling it’sApp.Backoffice.Endpoint, assets won’t be available if I’m accessing it through theforward. I mean, in development I’ll accesslocalhost:4001for developing thebackofficeand I can access the assets. But in production it won’t be able to reach the assets, right? (at least this is what I’m experiencing right now)…I don’t believe there is any reason that they need to exist together unless (I haven’t tried this yet) regarding authentication… Given this case where I separate both frontoffice and backoffice, given your experience, do you anticipate any issue with having authentication setup in both apps? As they’ll eventually have separated code for serialization and authentication it shouldn’t be a problem, right? But in the session-level do you think they could collide or something?
Sorry for all the questions! Thanks!
obsidienne
Hi,
Is it possible to add to Deploying on Heroku — Phoenix v1.8.8, a chapter about master proxy ?
My app has multiple phoenix app (scaffolded from phoenix 1.3 / different PORT) under the same umbrella and everything work in dev. And because I have to use heroku, a master_proxy is needed.
I have found using this forum the following gists: Websockets in Elixir with Cowboy and Plug · GitHub and Example MasterProxy for Elixir Umbrella applications supporting websockets · GitHub
But something more official/easy to find would be cool (one working with websocket).
Thanks