I’m wrapping up a Django/DRF based intranet-only CRUD application. I chose Django because I’m familiar with its ORM, architecture, deployment and of course quirks. I chose DRF because I it’s one of the easiest ways in Django-land to present a CRUD REST API, and I wanted to use JS-based forms rather than the native Django ones. Performance doesn’t really enter into it as the data volume is low and user count is in the single or double digits
I am relatively happy with the result. Using a mostly declarative language, I get easily-generated REST APIs with CRUD functionality, validation, nested relations*, custom queries and so on. This is because DRF comes with built-in tight-coupling with the Django ORM if you want to use it, and saves you having to redefine the fields types and validation all over again.
* However, getting nested relations updates to work was a major PITA. DRF doesn’t support those out of the box, since a safe general behaviour can’t be easily defined, so the instruction is to subclass the Serializer
and do whatever you want in the update
and create
methods.
Unfortunately, I found the internals of DRF are really convoluted and I’ve been banging my head on various edge cases for a long time, which has left a bitter taste in my mouth. I’m done now, and reasonably happy with the end-user functionality (it works!), but for the next one I would like to consider other options.
I haven’t really used Ecto or Phoenix for a CRUD application, but I’ve read a lot about them, tried out sample projects, and I’m monitoring the progress of the projects.
From this superficial experience, I would like to point out a few things:
- Ecto’s built-in fields are limited, but you can augment those yourself. There are already libraries out there with common fields. You are a bit dependent on Postgrex because adding custom fields to Postgrex seems a bit more involved.
- Echo Changesets (and schema less change sets?) should provide most, if not all, of the functionality required to do app-level conversion and validation from an external JSON document to a native Elixir struct, then updating or creating the entries in the DB.
- However it’s not clear to me if there is a need for another library/framework to more easily plug everything together, including converting validation errors to HTTP 400 with nice error messages etc.
- Phoenix doesn’t provide authentication/signup support so an external library must be selected.
- Phoenix/Plug can handle file upload, but leaves the details up to you. An external library must be selected to store and serve files.
- Phoenix doesn’t have any email functionality, so an external library must be selected (though the guides do suggest Bamboo for this.
- Django’s migrations automagically work most of the time, saving a huge amount of time. Ecto has migrations but you have to write them on your own.
- Django’s built-in admin is a very nice bonus while developing, while with Phoenix an external library must be selected.
- Django lacks a javascript/static assets pipeline, only providing you with a “collectstatic” command. You must select an external library or roll your own. Phoenix has brunch and has enough hooks to let you use your own.
- Django is locked in the “request/response” cycle. There is some ongoing work with Django Channels to surpass that though. Phoenix has first-class supports for websockets, including a javascript library.
- Django does a lot of work introspecting models in order to augment parts of the dev experience, with sometimes good and sometimes bad results.
- Django has pervasive autoreload, but no live-reload. Phoenix has autoreload and live reload.
(Have I missed something?)
I’m not going anywhere with this, just wanted to point these things out to start a conversation. I don’t see one way as particularly better over the other, just understandable differences considering the origins and age of each project. I don’t even mention the Elixir-specific benefits over Python (long running processes, parallelism and so on) because I believe in this forum they are a given.
That said, I believe there is space for an “opinionated Phoenix”, be it a custom generator or a pseudo-app that automatically pre-selects and integrates external libraries to provide some common functionality, perhaps providing a unified API that looks the same but differs on dev vs prod vs test. OTOH, perhaps it’s just an unneeded layer of abstraction?
I am just curious if people who have a previous Django/DRF experience can give their take on this?