Cześć. Piszę sobie projekt i mam pytanie odnośnie tego jak rozwiązać następujący problem. Mam formularz na froncie, który może wysłać dane o użytkowniku jak i jego dane kontaktowe w jednym post requeście. Dane kontaktowe są opcjonalne więc można je wprowadzić również później. Jak zaprojektowalibyście backend do takiego formularza?
  1. tworzę jeden endpoint, UserDto, które zawiera w sobie ContactDto i jeśli ContactDto jest poste/null to po prostu go nie tworzę. Tutaj zastanawiam się czy swagger byłby dobrze udokumentowany z opcjonalnymi polami do wypełnienia
  2. tworzę dwa osobne endpointy, dwa Dto dla Usera. Jeden taki sam jak w pkt. 1 i drugi bez relacji do ContactDto. Front end w zależności od tego co ma na wejściu, wybiera gdzie zrobić request
  3. robię dwa osobne endpointy, pierwszy tworzy zasób User, drugi zasób Contact. Front end uderza najpierw do Usera, później ze zwróconym id usera robi request by utworzyć kontakt. Problem, gdy user się utworzy, a kontakt nie, co wtedy powinien zwrócić taki formularz.
Jakieś inne opcje?
#programowanie #naukaprogramowania #java
Voltage

@otsochodzi A po co w ogóle dane kontaktowe osobno? Potrzebujesz one-to-many?

Shdhhxhxwhhzhdb

2 i 3 są nie reliable i mogą być manipulowane. Ja bym robił post na całości jako user, a zmiany jeśli potrzebne pchał w contact, dzięki temu masz relacje 1 do 1 i działanie frontendu/internetu nie jest potrzebne do spójności danych

otsochodzi

@Voltage ponieważ chce aby ktoś mógł je wprowadzić podczas dodawania użytkownika ale jeśli nie to może zrobić to później

satrix321

@otsochodzi Mam wrażenie, że niepotrzebnie komplikujesz sprawę. Oddzielne DTO dla kontaktu ma jakiś konkretny cel? Jeżeli nie to zawarłbym to jako część usera. Dla FE lepiej jeden endpoint na tworzenie usera z danymi kontaktowymi i drugi na aktualizację tych danych. Ale nawet jeżeli byś chciał oddzielne DTO, to i tak zrobiłbym jeden endpoint dla FE a na backendzie zrobił transakcję na tworzenie obu naraz.

JSON

@otsochodzi a jak wygląda JSON?

Voltage

@otsochodzi

ponieważ chce aby ktoś mógł je wprowadzić podczas dodawania użytkownika ale jeśli nie to może zrobić to później


No, na tym polega edycja usera, chyba że masz specjalny powód żeby wyodrębnić ten kontakt do innego modelu/formularza, to wtedy można kombinować nad lepszym rozwiązaniem, ale KISS i YAGNI

otsochodzi

@Voltage czyli zrobiłbyś jedno DTO dla informacji o użytkowniku i kontakcie, a następnie umożliwił edycję, dobrze rozumiem?

Voltage

@otsochodzi nie dałeś zbyt dokładnego opisu, więc przyjmuję że user będzie miał jedne dane kontaktowe, to raptem kilka pól w bazie więc tak, zrobiłbym UserDto z polami kontaktowymi, jak ktoś chce później dodać te dane to sobie edytuje. Zresztą to nie jest coś co trudno zmienić na dalszym etapie gdy np. potrzeba biznesowa rozdzielenia logiki faktycznie nastąpi.

otsochodzi

@Voltage czy DTO powinny w ogóle zawierać relacje do innych obiektów czy raczej wszystkie potrzebne dane powinny być w jednej klasie?. Pytam ogólnie ponieważ DTO powinno być lekkie więc umieszczanie tam relacji do obiektów z kolejnymi polami trochę łamie tę zasadę

Voltage

@otsochodzi Relacje powinieneś tworzyć w odpowiedniej warstwie, DTO najlepiej jak jest po prostu płaskie i zawiera dane które przenosisz między warstwami aplikacji. Najlepiej jak jest ich jak najmniej, wtedy nie musisz mieć od groma mapowań, więc jak chcesz zamieszczać kolejne klasy w DTO (jak np. wymieniłeś w pkt 1) to już trochę kłóci się z ideą DTO, przynajmniej tą purystyczną.

HmmJakiWybracNick

@otsochodzi IMO to trochę zależy od przypadku.

Jak masz prosty obiekt np. userName, password, email, phoneNumber, language - to nie ma sensu nic wydzielać. Ale jakbyś miał sporo pól, które można pogrupować i wydzielić, to ja bym już wydzielił, np.

userName,

password,

contanct: email, phoneNumber,

permanentResidenceAddress: country, city, streetName, streetNumber,

residenceAddress: country, city, streetName, streetNumber,

preferences: theme, language, timeZone


Ale to ja bym tak zrobił, może być to błędne myślenie i zaraz ktoś mnie wyjaśni ¯\_(ツ)_/¯

bzyku95

@otsochodzi 3. Nie rób tego, próba polegania na zrobieniu transakcji przez front jest fajna na localhoscie, później już nie


  1. To po prostu przeniesienie logiki z backendu na frontend, ja generalnie wolę jak to backend jest 'mądrzejszy', wtedy po prostu można pisać mniej jsa i mniej pchać do userów

  1. Jeden dto, używaj optionali, na podstawie tego dto możesz mieć 2 osobne metody w serwisie na 'czystego' usera albo nie, ale ta logikę możesz ładnie zenkapsulować już w kodzie aplikacji, natomiast wiadomo że tworzenie będzie postem, a update jeżeli całości to put, a tylko części to patch

Dla mnie DTO (jeżeli mówimy o takim serializowanym do jsona i używanym przez UI) powinno działać jak backend for frontend, czyli zawierać to co klient oczekuje w danym miejscu, bez dociągania requestami, np. jeżeli usera zawsze wyswietlasz z danymi do kontaktu, wpakuj razem, jeżeli dane to odrębny byt który czasem pokazujesz, a czasem nie, to osobno


Premature optimization is the root of all evil, dopóki nie wrzucasz kilku relacji z listami po setki obiektów, będzie dobrze

otsochodzi

@HmmJakiWybracNick @bzyku95 ale przecież na stronach, np. e commerce można spotkać formularze, która składają się z wielu danych, która są wysyłane w jednym DTO, być może jest ono posegregowane odpowiednio na osobne klasy ale wtedy i tak trzeba zadecydować, który kontroler ma te dane zapisać, który jest nadrzędny, prawda?

HmmJakiWybracNick

@otsochodzi Ja bym robił jak napisałeś, czyli wysyłasz to jednym dto, który w Twoim przypadku nazwałbym np. UserCreateData i który byłby albo płaską struktura, albo jak tych pól jest np. 60 (XD) to kompozycją. Przyjmowałby to jakiś UserController, który pchałby to do jakiejś fasady czy serwisu, który znowu używając jakiegoś mappera/konwertera robiłby z tego entity (o ile celem jest zapisanie tego do db), żeby zapisać do odpowiednich tabelek - oczywiście pamiętając o ogarnięciu tego w transakcji. Jak tych danych jest dużo, to może warto na frontendzie rozważyć zrobienie jakiegoś wizarda, żeby podzielić to na mniejsze kroki.

Zaloguj się aby komentować