noam87
Should we Separate Ecto From Phoenix in Umbrella App?
Hey, so we have an umbrella app, where the API is served by a Phoenix app, and then kick off a bunch of apps to perform application logic. The result from those calculations needs to be stored in the DB as well. So, for example:
- User calls API and updates some information on his profile.
- The data is stored in DB.
- Another app in the umbrella is kicked off to perform some aync job (collect more data from external API, run some calculations, etc.)
- Result from those calculations need to also be stored in the DB, but that module does not have the Repo as a dependency.
So I’m considering either:
-
Separating Ecto from Phoenix, and have a “DB” app in the umbrella that handles all the db stuff, and then including that app in both the API and any other modules that need to talk to the DB as a dependency.
-
Have the modules send a message back to Phoenix API that called it with its result, and then have the Phoenix app handle all db requests.
Most Liked
christhekeele
I’m experimenting with this now, and liking the following setup:
mix new project --umbrellacd project/appsmix new db --sup --module Project.DBmix new app --sup --module Project.Appor what have you for other otp appsmix phoenix.new site --module Project.Site- Remove
postgrexfrom site deps and applications, leavephoenix_ecto - Add
{:db, in_umbrella: true}to site and other app deps, also add:dbto theapplication:applicationsconfig in theirmix.exss - Add
ectoandpostgrexto db deps and applications mv site/lib/site/repo.ex db/lib/db/repo.ex- Rename all occurrences of
Project.Site.RepotoProject.DB.Repo mv site/priv/repo db/privmv site/web/models db/lib/db- Mirror phoenix’s
config/<env>.exsfiles setup in db - Copy the
/priv/static/and/config/prod.secret.exsrules fromsite/.gitignoretodb/.gitignore - Move
ecto_reposconfiguration todb/config.exs - Move the repo adapter config in each site
config/<env>.exsfile to db - Make sure the
"phoenix"and"phoenix_html"filepaths in yoursite/package.json’s"dependencies"reference"file:../../deps/<dep>" - Stop using phoenix model generators, use
mix ecto.gen.migration -r Project.DB.Repofrom the db app - Freely access models, queries, etc from your other apps as
Project.DB.<Model>
I think that’s about everything necessary that I did.
Further optional conveniences:
- Rename databases from
"site_<env>"in these adapter configs to"project_<env>" - Delete
def model...fromsite/web/web.ex - Make a
db/lib/db/model.exwith a__using__macro with thequotefrom yourProject.Site.Web.modelyou just deleted - Replace all occurrences of
use Project.Site.Web, :modeltouse Project.DB.Modelindb/lib/db/models - Move
site/mix.exs’s ecto aliases todb/mix.exs(optionally under a newdbnamespace instead ofecto) - Move
site/mix.exs’s test alias to the umbrella app’smix.exs - I removed all of the references to
Project.DB.Repoinsite/web/web.exand other Ecto stuff and instead made it so that you canuse Project.DB.<Model>to get aliases for both that model and the repo, then used that instead atop my controllers and channels. Ditto with myProject.DB.<Query>s. - I changed all my otp app names to be prefaced with “project”, which requires changes in
mix.exss,config/files,db/lib/db/repo.ex,site/lib/site/endpoint.ex, andsite/web/gettext.ex. You also have to rename your folders in theappsfolder to follow the otp name, prefix and all, to avoid weird umbrella app and phoenix hot code reloading issues. - I experimented with moving everything from
site/webintosite/lib/site. You have to remove"web"from the site’s"elixirc_paths"and rename references to thewebdir withlib/sitein brunch stuff, and change the root of your templates within yoursite/lib/web.exdirectory. However, this destroys hot code reloading so I can’t say I recommend it.
michalmuskala
That is my preferred way of structuring apps as well. At least two apps in an umbrella - a domain one and an api one. First handles all the persistence and knows nothing of https, the second one calls plain function from the first one and knows nothing of ecto or any other persistence mechanism.
noam87
Update: so yeah we did end up separating Ecto from Phoenix, and it was easy to do and easy to work with. There’s only some mild annoyances when running generators and stuff like that.
Now building my second Elixir project the same way. This time it’s a GraphQL API (using Absinthe) so there’s not even an HTML layer or controllers, making Phoenix a very thin layer for organising plugs and GraphQL schemas in a standard way really.
Here’s my short cheat sheet for starting projects this way: Redirecting...
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
- #advent-of-code
- #elixirconf-us
- #distillery
- #processes
- #forms
- #api
- #metaprogramming
- #security
- #performance








