Angular - pytanie o komunikację component->back-end. Czy dobrze to robie?

Angular - pytanie o komunikację component->back-end. Czy dobrze to robie?
RoboCat
  • Rejestracja:prawie 7 lat
  • Ostatnio:prawie 3 lata
  • Postów:32
0

Witam,
Zaczynam przygodę z angular2 i mam małe pytanie czy myślę w dobym kierunku czy jednak jest to za duży mix i pójść prostsza drogą.
(( obsługę wyjątków i błędów ominąłem aby skrócić kod))
Chciałbym wiedziec czy tak to się robi czy za dużo kombinuję i lepiej to skrócić że np. component będzie miał injected repo i dostęp do funkcji cruda.
Programuję hobbistycznie więc proszę o wyrozumiałość :D (chciałbym pracować nawet jako junior ale boję się że mam za małą wiedzę)
Back-end to api które piszę w Asp.net core2

Na razie napisałem tak: (Na przykładzie pobierania wszystkich użytkowników z back-endu)
Mam klase abstrakcyjną:

Kopiuj
Repository<T extends MyItems> 

z funkcjami CRUD np:

Kopiuj
getAll() : Observable<T[]>
    {
        return this.http.get(
            `${this.url}/${this.endpart}`, this.auth.getHeader()).pipe(map((data: any) => data.json() as T[]));
    }

Od niej tworzę klasę repo dla np modelu User: (takie repo mogę powiększyć o funkcje wymagane w konkretnym przypadku/modelu)

Kopiuj
export class UsersRepository extends RepositoryService<User>

Następnie mam klasę service która ma dostęp do repo. np. Users.service.ts (tutaj dane odebrane z repo (User[]) będą mapowane na UserDto[] i odbierane w component:

Kopiuj
getAll() {
        return new Promise(resolve=> {
            this.usersRepo.getAll().subscribe(
                data => {
                    var userDtos: UserDto[] = [];
                    data.forEach(
                        (user) => 
                        {
                            // mapowanie będzie docelowo lepiej rozwiązane ale narazie nie posiadam wiedzy żeby to zrobić
                            userDtos.push(<UserDto> { id: user.id, username : user.username, email : user.email }); 
                    })
                    resolve(userDtos);
                })
        })
    }

Dane odbierane i przetwarzane są przez component i dalej przekazane do template: (tutaj przykład jakby to miało wyglądać):

Kopiuj
getAllUsers()
{
    var userDtos: UserDto[] = [];

    this.usersService.getAllTmp().then(
    (data:UserDto[]) => {
        if(data.length > 0) {
            data.forEach(
                (user) => 
                {
                    console.log("name: " + user);
                })
        }})
}

modele: (User.model.ts oraz UserDto.model.ts) skrócone do minimum.

Kopiuj
//User
export class User extends MyItems
{
    username: string;
    email: string;
    password: string; // never stored used when request login/register
    token: string;
}
//UserDto
export class UserDto extends MyItems
{
    id: number;
    username: string;
    // UserDetails here
}

Myślałem żeby klasy UserService itp również zrobić jako generic<T> z dodatkową serializacją modeli z Model -> Dto.
Tylko nie wiem czy nie za duzo kombinuje "na około"...

Z góry dziękuję za podpowiedzi i nakierowanie w odpowiednim kierunku :D

OM
  • Rejestracja:ponad 10 lat
  • Ostatnio:prawie 5 lat
  • Postów:100
0

Jak dla mnie za dużo kombinujesz. Takie rzeczy są ok na backendzie gdzie zazwyczaj dane z UI =/= dane z bazy.
W projekcie mamy po prostu coś takiego (przykład):

Kopiuj
@Injectable((
export service UserService {
   getUser = (): Observable<UserModel> => {
      return this.http.get('/api/user/');
   }

   getUserDetails = (id: number): Observable<UserDetailsModel> => {
      return this.http.get(`/api/user/${id}`);
   }
}

Na szczęście nie zdarzyło się jeszcze żebym musiał tutaj coś mapować na frontendzie. Takie mapowania jak dla mnie wprowadzają dodatkowy zamęt - coś się nie zgadza przy np zapisywaniu zmian i trzeba szukać widok -> mapper -> "bóg wie co jeszcze" -> api zamiast sprawdzić "z api przyszło, że pole o nazwie Login jest złe to sprawdzę pole login w widoku".
Mapować to ew możesz jak podpinasz się pod zewnętrzne api/inny system i tam mają straszny syf albo dane z innego systemu później musisz zapisać do jeszcze innego.

Kopiuj
        return this.http.get(
            `${this.url}/${this.endpart}`, this.auth.getHeader()).pipe(map((data: any) => data.json() as T[]));

Angularowy HttpClient domyślnie mapuje dane na json więc to jest bezsensu.

Kopiuj
getAll() {
        return new Promise(resolve=> {
            this.usersRepo.getAll().subscribe(
                data => {
                    var userDtos: UserDto[] = [];
                    data.forEach(
                        (user) => 
                        {
                            // mapowanie będzie docelowo lepiej rozwiązane ale narazie nie posiadam wiedzy żeby to zrobić
                            userDtos.push(<UserDto> { id: user.id, username : user.username, email : user.email }); 
                    })
                    resolve(userDtos);
                })
        })
    }

Lepiej nie mieszać promisów z observable dopóki nie jest do niezbędne.

Kopiuj
//User
export class User extends MyItems
{
    username: string;
    email: string;
    password: string; // never stored used when request login/register
    token: string;
}
//UserDto
export class UserDto extends MyItems
{
    id: number;
    username: string;
    // UserDetails here
}

Modele powinny być raczej interfejsami i odzwierciedlać to co dostajesz z API.

I taka mała porada jeszcze: możesz zrobić sobie swoją implementację http serwisu tzn serwis który będzie miał takie same metody jak HttpClient (get, put, post, delete, ...). Będziesz wtedy wywoływał ten serwis bez dodawania zawsze

Kopiuj
this.auth.getHeader()

A jak kiedyś będzie trzeba na sztywno coś dodawać np header jakiś to zamiast w 100+ miejscach dodasz w jednym serwisie.

edytowany 2x, ostatnio: OverMorda
RoboCat
  • Rejestracja:prawie 7 lat
  • Ostatnio:prawie 3 lata
  • Postów:32
0

No tak myślałem że za dużo kombinowania :D Wystarczy że już mam tak na back-endzie.

Czy jest jakis "duuuży" minus mieszania promise z observable? Musiałem tak użyć ponieważ wszystko działa async. i w component musiałem czekać na "powrót" danych.
Skrócę to sobie przy najbliższej okazji.
Implementacja swojego http to tez dobry pomysł. W header przesyłam token usera do api.

Czyli to jest zbedne?

Kopiuj
map((data: any) => data.json() as T[]))

Dzieki za rady.

OM
  • Rejestracja:ponad 10 lat
  • Ostatnio:prawie 5 lat
  • Postów:100
0

Czy jest jakis "duuuży" minus mieszania promise z observable? Musiałem tak użyć ponieważ wszystko działa async. i w component musiałem czekać na "powrót" danych.

To zrób coś takiego:

Kopiuj
getAll() {
        return Observable.create(observer=> {
            this.usersRepo.getAll().subscribe(
                data => {
                    var userDtos: UserDto[] = [];
                    data.forEach(
                        (user) => 
                        {
                            // mapowanie będzie docelowo lepiej rozwiązane ale narazie nie posiadam wiedzy żeby to zrobić
                            userDtos.push(<UserDto> { id: user.id, username : user.username, email : user.email }); 
                    })
                    observer.next(userDtos);
                })
        })
    }

Generalnie nic się nie stanie jak używasz obydwu wersji ale wprowadza to niepotrzebne zamieszanie. Wszystko co możesz zrobić z Promise zrobisz także w rxjs.

Czyli to jest zbedne?

Tak

edytowany 1x, ostatnio: OverMorda
RoboCat
  • Rejestracja:prawie 7 lat
  • Ostatnio:prawie 3 lata
  • Postów:32
0

Czyli to będzie jakby "observable do observable"?
Dzięki bardzo, to mi się akurat przyda, dopiero zacząłem angular i na razie rozkminiam co jak robić.

OM
  • Rejestracja:ponad 10 lat
  • Ostatnio:prawie 5 lat
  • Postów:100
0

Observable który zostanie rozwiązany jak ten inny się zakończy.

RoboCat
  • Rejestracja:prawie 7 lat
  • Ostatnio:prawie 3 lata
  • Postów:32
0

Tak, niewiedziałem jak to ładnie opisać.
Wielkie dzięki.

Zarejestruj się i dołącz do największej społeczności programistów w Polsce.

Otrzymaj wsparcie, dziel się wiedzą i rozwijaj swoje umiejętności z najlepszymi.