zoedsoupe

zoedsoupe

How about "DTOs" on controllers? (Data Transfer Objects)

In our app, we are trying to apply a hexagonal architecture. We have the concept of internal schemas, generally ecto embedded schemas or schemaless changesets that perform some validation or data transformation. Its easier to transport internal data with this logic.

The workflow:

  • App receives an incoming message (API, Kafka)
  • Controller uses an Adapter to parse an internal schema
  • Controller passes this schema to the context
  • Render response

However, we have some problems:

  • We have several external providers (Kafka, other APIs, frontend) that can have different fields.
  • We would need a way to create different versions of a schema, for an API
  • We would like to move this validation with schemas more to the edge of our web layer

The idea is somewhat the same as a DTO (Data Transfer Object), but it would be only flat maps only to do validation and maybe reject the invalid incoming message.

Does anyone make something similar to this? Does this make sense at all?

Most Liked

kokolegorille

kokolegorille

You might find this highly related :slight_smile:

and

I prefer CQRS/ES because I think it fits well with signal and processes.

This book, although not in Elixir, but in F#, is in my recommendation list

beepbeepbopbop

beepbeepbopbop

The biggest takeaway I’ve personally found implementing these sort of patterns in Elixir (or probably in any functional language), is the concept of “functional core, imperative shell”. I would go on to say that it is the overriding principle in your classic hexagonal architecture, CQRS included (especially in Commanded aggregates).

“Functional core, imperative shell” as a concept does not require as much ceremony as one would think. Certainly nothing on the level of classic OOP languages, although there are a couple of discussion points to have had.

One such argument is the value of persistence and transactionality in your core application. Storage is such a key component to a vast majority of applications that they are intrinsically link to the core. Proponents point out that this is a serialisation process, an imperative shell that needs to be completely isolated from the core system. In the book Designing Elixir Systems with OTP: Write Highly Scalable, Self-Healing Software with Layers by James Edward Gray, II and Bruce A. Tate, it pushes it to a different layer as implied in the table of contents:

  • Assemble Your Components
    • Add Persistence as a Boundary Service

In this case, your core systems have no idea about database structures and this requires an encoding/decoding layer that you’ll have to write. While somewhat tedious, it is “technically” correct and if there’s one word to summarise the process of implementing application with the “functional core, imperative shell”, tedious could be a word one would use.

Maybe you don’t really need all this and you place transactionality as part of the domain itself. This certainly makes the rules simpler. In that case, you can model your code in a “light” style of functional core that contexts give you. An excellent primer to get your head in this zone are a series of articles by Sasa Juric:

Just don’t use it as the “source of truth” for all things related to code structure and standards. It’s a set of very well explained decisions, but it would be wrong to conflate it as the “canonical way” to build Elixir applications.

kokolegorille

kokolegorille

Your structure is not conventional, and it looks You are trying to do Ruby in Elixir, but Elixir is not Ruby.

Changesets are the usual way to deal with DTO, and You might have many in the same schema. For example one for kafka, one for another provider, etc. Each one with custom validation, and casting rules.

Is there a reason to have business logic in the controller?

Last Post!

kokolegorille

kokolegorille

You might think of your data first. And functions to transform them. Functions are first class citizen.

input → function → output

If You can remember input type, and output type of your functions, You can build pipelines of composable functions.

Then, You might think of where You want to add concurrency to your application, because You are on the BEAM.

This is not mandatory if You use Phoenix, because it’s done for You.

In Your case…

%AnyStruct{}
|> AnyStruct.changeset(dto)
|> Repo.update (or insert)

-> {:ok, %AnyStruct{}} | {:error, changeset}

Where Next?

Popular in Discussions Top

CharlesO
Erlang :list.nth simple, but 1 - based nth(1, [H|_]) -> H; nth(N, [_|T]) when N > 1 -> nth(N - 1, T). Elixir Enum.at … coo...
New
restack_oslo
Hello, Please pardon me for any faux paux. I am 46 and this is my first time on a forum of any kind. I wanted to to get answers from tho...
New
sergio
There’s a new TIOBE index report that came out that shows Elixir is still not in the top 50 used languages. It also goes on to call Elix...
New
dogweather
I wrote this comment on r/haskell, and it’s not popular there. :wink: But I think I’m on to something… Haskell reminds me of Java, and e...
New
Fl4m3Ph03n1x
Background This question comes mainly from my ignorance. Today is Black Friday, one of my favorite days of the year to buy books. One boo...
New
marciol
Please, let me know if this kind of discussion already took place in another topic . Hi all, how do you consider if is better to build ...
New
pillaiindu
I want to convert a Phoenix LiveView CRUD website to a CRUD mobile app. What do you think is the easiest way to do so?
New

Other popular topics Top

Qqwy
Original source of discussion: This topic on the Pragmatic Programmers’ Functional Web Development with Elixir, OTP, and Phoenix forum. ...
New
vonH
In asking this question I am more interested about the expressiveness of the language itself and less concerned about the availability of...
New
dokuzbir
I want to highlight html closing tags when i click a html tag. That works in .html files but doesnt work for html.eex templates. How can...
New
Darmani72
If I have a post route which an argument: post /my_post_route/:my_param1, MyController.my_post_handler How would get the post params ...
New
AngeloChecked
What learn first? Rust or Elixir Hi Elixir community! I’m here because i want learn a new language. I’m a junior developer and mainly i ...
New
senggen
Erlang/OTP 25 [erts-13.2.2] [source] [64-bit] [smp:8:8] [ds:8:8:10] [async-threads:1] 15:22:35.803 [error] gen_event {lager_file_backend...
New

We're in Beta

About us Mission Statement