In my experience the key point of an API is the “I” or interface. The API is one way of looking at, and interacting with, a domain that is modeled in computer code. Another example of an interface is a Graphical User Interface.
I know… I sound like an idiot spouting terminology definitions that are self-evident. Please bear with me.
Important to the ideas here is the fact that you have a model and that model lives in a problem domain. Domain Driven Design provides you with a set of concepts - tools to help you design a model that will solve specific problems in a domain using a computer. That activity, generally speaking is valid work in-of-itself. If you don’t solve the problem you’re work is wrong or incomplete. The result of solving the problem gives you source code that presents a programmatic interface to the solution. The term I personally use for this is the implementation model of the solution.
Now you want to expose that programmatic interface to the outside world. One of the difficulties with API design is that it is another programmatic interface, and so our first instincts are to simply expose that programmatic interface through the API layer. I cannot speak for others, but my experience has been that this is a mistake. I have found that the implementation of the solutions - the models that make up the solution in the domain can change even when you don’t want the API to change. (you don’t want to impose the burden of an API change on folks using the API.
Having said that, here are the options you presented and my personal opinions:
- I could forget about DDD. Have RESTful resources and API endpoints that interact directly with them
If your domain and problems are very, very simple then you might get away with this for a time. I have found that simple solutions like this, if successful, have the annoying tendency to grow in complexity and quickly overwhelm this approach. You can get away with this so long as you are willing to refactor on a hair trigger if things get even slightly more complex. This is a great approach for prototyping but you have to have the discipline to throw out the prototype rather than trying to grow it.
- I could forget about REST and have the API endpoints mimic the domains and their methods
I have had very, very bad experiences with this approach. Exposing the implementation details of your system through an API in this fashion leads a painfully unstable environment for the folks unfortunate enough to have to use your API. When your core model changes - to accommodate new solutions, your API must change right along with it. Either that, or YOU must compromise your core model in order to maintain support for older versions of the API.
Now, having said this - it is the case that some aspects of your core model will be exposed to your customers. If your problem space involves setting up virtual machines then chances are you will have some kind of virtual machine entity both in the programmatic, core domain model, and in the conceptual model presented through the interface (and you want that conceptual model as presented through the interface to be fairly consistent between all interfaces API, GUI, or otherwise). But I suggest avoiding the temptation to tying user-facing models directly to programmatic implementation models.
- I could have RESTful endpoints that interact wit h the Restful resources through domains
I, personally, have had the most success with this. Modeling the solution, and it’s programatic interface, in a domain layer, and then having (one or more) separate Interface Layer(s) built on top of it. It gives me the most flexibility to change the core model AND adapt to those changes in the interface layer. The Interface layer gives you a point of transition - a translation or anti-corruption space - between the user’s mental model (or conceptual model) of your system and the actual implementation model. In functional programming/transformation terms it’s the point at which you transform the user’s intent into actual execution in your domain model.
Now… up to this point I haven’t mentioned Phoenix at all. As others have pointed out, Phoenix itself is rather agnostic to how you do or do not tie your API to your programmatic interface. What I have tried to do (in a very small space, and perhaps with not as much brevity as folks might like) is to offer some benefits of my hard-won (or hard-worn) experience.
In terms of resources, and things to read, several years ago I found a lot of support and help from a book by a company called apigee:
I have no connection to the company and was never in a position to buy any of their products, but I did enjoy their white papers on API design and style.
I don’t have direct links to other reading I did on the subject I’m afraid. At the time I was looking at “API Gateways” and found that the folks who design such things usually had something to say on the subject of API design.