Czy powinieneś napisać swój back-end jako API?

322

Dzisiaj miałem gorącą dyskusję na temat naszej aplikacji MVC. Mamy stronę internetową napisaną w MVC ( ASP.NET ) i zwykle jest zgodna ze schematem robienia czegoś w widoku -> uderz w kontroler -> kontroler buduje model (wywołuje menedżera, który pobiera dane, buduje model w sama metoda kontrolera) -> model przechodzi do widoku -> spłucz i powtórz.

Powiedział, że nasz kod jest zbyt ściśle powiązany. Na przykład, jeśli chcielibyśmy mieć również aplikację komputerową, nie moglibyśmy użyć naszego istniejącego kodu.

Rozwiązaniem i najlepszą praktyką, którą powiedział, jest zbudowanie interfejsu API, a następnie zbudowanie strony internetowej na podstawie interfejsu API, a następnie zbudowanie aplikacji komputerowej, aplikacji mobilnej itp. Jest bardzo proste.

Z różnych powodów wydaje mi się to złym pomysłem.

W każdym razie nie wydaje mi się, że mogę znaleźć coś w Google, co mogłoby omówić tę praktykę. Czy ktoś ma jakieś informacje o zaletach, wadach, dlaczego warto, dlaczego nie lub dalszej lektury?

Niektóre powody uważam za zły pomysł:

  • To zbyt abstrakcyjne, żeby uruchomić backend z API. Próbujesz uczynić go zbyt elastycznym, co sprawi, że będzie to niemożliwy do zarządzania bałagan.

  • Wszystkie rzeczy wbudowane w MVC wydają się bezużyteczne, takie jak role i uwierzytelnianie. Na przykład atrybuty i bezpieczeństwo [Autoryzuj]; będziesz musiał rzucić własne.

  • Wszystkie wywołania interfejsu API będą wymagać dołączenia informacji o bezpieczeństwie, a będziesz musiał opracować system tokenów i tak dalej.

  • Będziesz musiał napisać pełne wywołania API dla każdej funkcji, jaką Twój program kiedykolwiek wykona. Prawie każda metoda, którą chcesz wdrożyć, będzie wymagała uruchomienia interfejsu API. Pobierz / zaktualizuj / usuń dla każdego użytkownika oraz wariant dla każdej innej operacji, np. Zaktualizuj nazwę użytkownika, dodaj użytkownika do grupy itp. Itd., A każda z nich będzie odrębnym wywołaniem API.

  • Tracisz wszelkiego rodzaju narzędzia, takie jak interfejsy i klasy abstrakcyjne, jeśli chodzi o interfejsy API. Rzeczy takie jak WCF mają bardzo słabe wsparcie dla interfejsów.

  • Masz metodę, która tworzy użytkownika lub wykonuje jakieś zadanie. Jeśli chcesz utworzyć 50 użytkowników, możesz po prostu zadzwonić do niego 50 razy. Gdy zdecydujesz się zastosować tę metodę jako interfejs API, lokalny serwer może połączyć się z nią nazwanymi potokami i nie ma problemu - twój klient pulpitu też może go trafić, ale nagle twoje masowe tworzenie użytkowników będzie wymagało 50-krotnego udoskonalenia interfejsu API nieźle. Musisz więc stworzyć metodę zbiorczą, ale tak naprawdę tworzysz ją tylko dla klientów stacjonarnych. W ten sposób musisz a) zmodyfikować interfejs API w oparciu o to, co się z nim integruje, i nie możesz po prostu bezpośrednio z nim zintegrować, b) wykonać o wiele więcej pracy, aby utworzyć dodatkową funkcję.

  • YAGNI . O ile nie planujesz specjalnie napisać dwóch identycznie działających aplikacji, na przykład jednej aplikacji internetowej i jednej aplikacji Windows, jest to ogromna ilość dodatkowych prac programistycznych.

  • Debugowanie jest znacznie trudniejsze, gdy nie można przejść od końca do końca.

  • Wiele niezależnych operacji, które będą wymagały wielu ruchów w przód iw tył, na przykład jakiś kod może uzyskać bieżącego użytkownika, sprawdzić, czy użytkownik jest w roli administratora, uzyskać firmę, do której należy użytkownik, uzyskać listę innych członków, wysłać im wszystkich email. Wymagałoby to wielu wywołań interfejsu API lub napisania niestandardowej metody dla konkretnego zadania, które chcesz, a jedyną korzyścią tej metody byłaby szybkość, ale wadą byłoby to, że byłaby nieelastyczna.

  • Prawdopodobnie kilka innych powodów, które są po prostu z mojej głowy.

Wydaje mi się, że chyba, że ​​naprawdę potrzebujesz dwóch identycznych aplikacji, to naprawdę nie jest tego warte. Nigdy nie widziałem aplikacji ASP.NET zbudowanej w ten sposób, musisz napisać dwie osobne aplikacje (interfejs API i kod) i kontrolować je również w obu wersjach (jeśli strona użytkownika otrzyma nowe pole, „ d muszę jednocześnie zaktualizować interfejs API i kod używający, aby zapewnić brak negatywnych efektów lub włożyć dużo dodatkowej pracy w utrzymanie jego niezawodności).


Edycja: Kilka świetnych odpowiedzi, naprawdę zaczynam rozumieć, co to wszystko znaczy teraz. Więc, aby rozwinąć moje pytanie, w jaki sposób stworzyłbyś aplikację MVC pod kątem tej struktury API?

Na przykład masz witrynę internetową, która wyświetla informacje o użytkowniku. W ramach MVC masz:

Widok - (CS) strona HTML, która wyświetla kontroler UserViewModel - Wywołuje GetUser () i tworzy UserViewModel, który przekazuje do klasy menedżera widoku (rodzaj interfejsu API), który ma metodę GetUser.

Kontroler obsługuje GetUser (), ale chcesz też aplikację komputerową. Oznacza to, że Twój GetUser musi zostać ujawniony za pośrednictwem pewnego rodzaju interfejsu API. Możesz chcieć mieć połączenie TCP, WCF lub być może zdalne. Potrzebujesz także aplikacji mobilnej, która będzie RESTful, ponieważ trwałe połączenia są niestabilne.

Czy napisałbyś zatem API dla każdego z nich, usługę internetową WCF, która ma metodę GetUser () i tylko kod return new UserManager().GetUser()? I metoda web api mvc 4, która robi to samo? Nadal wywołujesz GetUser bezpośrednio w metodzie kontrolera MVC?

Czy też wybrałbyś rozwiązanie, które działałoby dla wszystkich trzech (usługa REST interfejsu API sieci Web) i zbudowałbyś na nim wszystko, więc wszystkie trzy aplikacje wykonują wywołania API (te mvc, na maszynę lokalną).

A czy to tylko teoretyczny idealny scenariusz? Widzę duże koszty ogólne w rozwoju w ten sposób, szczególnie jeśli musisz się rozwijać w sposób, który pozwoli ci wykonywać operacje w sposób RESTful. Myślę, że niektóre z nich zostały ujęte w odpowiedziach.


Edycja 2: Po przeczytaniu większej ilości rzeczy umieściłem poniżej komentarz, który moim zdaniem może to wyjaśnić. To pytanie jest podchwytliwe. Jeśli napiszesz back-end jako API, pomyliłem myśl, że powinna istnieć jedna usługa internetowa, do której wszystko (aplikacja mvc, aplikacja na komputer, aplikacja mobilna) wzywa.

Doszedłem do wniosku, że tak naprawdę powinieneś upewnić się, że twoja warstwa logiki biznesowej jest prawidłowo oddzielona. Patrząc na mój kod, robię to już - kontroler zadzwoni GetUser()do menedżera, a następnie utworzy z niego model widoku do renderowania za pomocą widoku. Tak naprawdę warstwa logiki biznesowej jest interfejsem API. Jeśli chcesz zadzwonić z aplikacji komputerowej, musisz napisać coś w rodzaju usługi WCF, aby ułatwić jej wywołanie. Wystarczy nawet wywołać metodę WCF GetUser()zawierającą kod return MyBusinessLayer.GetUser(). API jest więc logiką biznesową, a API WCF / web itp. To po prostu fragmenty kodu, które pozwalają aplikacjom zewnętrznym na wywołanie go.

Jest więc pewien narzut, polegający na tym, że musisz zawinąć warstwę logiki biznesowej w różne interfejsy API w zależności od tego, czego potrzebujesz, i będziesz musiał napisać metodę API dla każdej operacji, którą chcesz wykonać w innych aplikacjach, a ponadto będziesz musiał wymyślić sposób przeprowadzenia uwierzytelnienia, ale w większości jest taki sam. Trzymaj logikę biznesową w osobnym projekcie (bibliotece klas), a prawdopodobnie nie będziesz mieć problemu!

Mam nadzieję, że ta interpretacja jest poprawna. Dziękujemy za całą wygenerowaną dyskusję / komentarze.

NibblyPig
źródło
25
Czy możesz podać przyczyny, dla których uważasz, że byłby to zły pomysł? W dzisiejszych czasach muszę przyznać, że nie widzę powodu, aby tego NIE robić. Ułatwia to między innymi przenoszenie aplikacji na różne platformy i zapewnia dużą elastyczność interfejsu, nawet bez dotykania kodu zaplecza ...
Laurent S.,
12
@SLC: Kiedy mówisz API, masz na myśli interfejs API usługi internetowej, taki jak interfejs SOAP lub REST? Ponieważ powinieneś uczynić back-end API, ale nie powinieneś uczynić go usługą internetową.
JacquesB,
7
@IanNewson „aplikacja mobilna ma na przykład mniej funkcji”. Nigdy nie słyszałem przekonującego powodu, dla którego aplikacje mobilne powinny być obywatelami drugiej kategorii ... (ale wydaje się, że wszyscy robią to w ten sposób)
Michael
3
@IanNewson może wtedy to tylko ja ... ale zawsze jestem zahamowany, ponieważ nie jestem w stanie nic zrobić na telefonie komórkowym do tego stopnia, że ​​robię niewiele na telefonie komórkowym
Michael
11
Mówisz, że YAGNI ma zastosowanie, ale moje doświadczenie polega na tym, że aplikacje albo co kilka lat otrzymują przepisywanie interfejsu użytkownika, albo wszyscy narzekają, że go potrzebują. Na pewno byłoby miło, gdybyśmy nie stracili logiki firmy, ponieważ pojawiła się nowa technologia front-end.
corsiKa

Odpowiedzi:

282

Tak, powinieneś.

Nie tylko sprawia, że ​​Twój back-end nadaje się do ponownego użycia, ale pozwala na większe bezpieczeństwo i lepszy design. Jeśli piszesz backend jako część jednego systemu, tworzysz monolityczny projekt, który nigdy nie jest łatwy do rozszerzenia, wymiany lub ulepszenia.

Jednym z obszarów, w którym jest to obecnie popularne, są Microservices . Gdzie backend jest podzielony na wiele małych (lub nawet dużych) usług, z których każda zapewnia interfejs API wykorzystywany przez system klienta. Jeśli wyobrażasz sobie korzystanie z wielu zewnętrznych źródeł danych w swojej aplikacji, zdajesz sobie sprawę, że już to robisz.

Kolejną korzyścią jest to, że budowę i utrzymanie każdej usługi można przekazać innemu zespołowi, mogą oni dodawać do niej funkcje, które nie wpływają na żaden inny zespół produkujący produkty. Dopiero po ich zakończeniu i wydaniu usługi zaczynają dodawać funkcje do produktu, aby je wykorzystać. Może to sprawić, że rozwój będzie znacznie płynniejszy (choć ogólnie potencjalnie wolniejszy, można uzyskać lepszą jakość i zrozumiałość)


Edycja: OK. Widzę twój problem. Myślisz o API jako zdalnej bibliotece. To nie jest. Pomyśl o usłudze jako o usłudze dostarczania danych. Wywołujesz usługę, aby uzyskać dane, a następnie wykonać operacje na tych danych lokalnie. Aby ustalić, czy użytkownik jest zalogowany, wywołaj „ GetUser”, a następnie sprawdź na przykład 'logged on'wartość. ( YMMV oczywiście z tym przykładem).

Twój przykład masowego tworzenia użytkowników to tylko wymówki - nie ma tutaj różnicy, cokolwiek byś zrobił w systemie monolitycznym, nadal można zrobić w architekturze usług (np. Przekazałeś szereg użytkowników do masowego tworzenia lub jeden do utworzenia. Nadal możesz zrobić dokładnie to samo z usługami).

MVC jest już oparte na koncepcji usług izolowanych, tylko frameworki MVC łączą je w jeden projekt. To nie znaczy, że tracisz wszystko oprócz dołączonych pomocników, które daje ci twój framework. Użyj innej struktury, a będziesz musiał użyć różnych pomocników. Lub w tym przypadku kręcenie własnych (lub dodawanie ich bezpośrednio za pomocą biblioteki).

Debugowanie jest również łatwe - możesz dokładnie przetestować API w izolacji, więc nie musisz debugować w nim (i możesz debugować od końca do końca, Visual Studio może dołączyć do kilku procesów jednocześnie).

Rzeczy takie jak dodatkowa praca przy wdrażaniu zabezpieczeń to dobra rzecz. Obecnie, jeśli umieścisz cały kod w swojej witrynie, jeśli haker uzyska do niego dostęp, to również zyska dostęp do wszystkiego, łącznie z DB. Jeśli podzielisz go na API, haker może zrobić niewiele z twoim kodem, chyba że zhakuje również warstwę API - co będzie dla nich niezwykle trudne (zastanawiałeś się kiedyś, w jaki sposób atakujący zdobywają szeroką listę wszystkich użytkowników witryny lub szczegółów DW? To dlatego, że zhakowali system operacyjny lub serwer sieciowy i miał bezpośrednie połączenie z bazą danych, gdzie mogli select * from usersz łatwością działać „ ”).

Powiem, że widziałem wiele stron internetowych (i aplikacji klient-serwer) napisanych w ten sposób. Kiedy pracowałem w branży usług finansowych, nikt nigdy nie napisałby strony internetowej typu „wszystko w jednym”, częściowo dlatego, że stanowi to zbyt duże ryzyko dla bezpieczeństwa, a częściowo dlatego, że dużo rozwoju to dość GUI zamiast stabilnego (tj. Starszego) przetwarzania danych zaplecza systemy. Łatwo jest udostępnić system DP jako stronę internetową przy użyciu architektury stylu usługi.

2. edycja: Niektóre linki na ten temat (dla PO):

Pamiętaj, że mówiąc o nich w kontekście strony internetowej, serwer WWW powinien być uważany za warstwę prezentacji, ponieważ to klient wywołuje inne warstwy, a także dlatego, że konstruuje widoki interfejsu użytkownika wysyłane do przeglądarki w celu renderowania. Jest to duży temat i istnieje wiele sposobów zaprojektowania aplikacji - zorientowanych na dane lub zorientowanych na domenę (zazwyczaj uważam, że są one „czystsze”, ale YMMV ), ale wszystko sprowadza się do przyklejenia warstwy logicznej pomiędzy twój klient i twoja baza danych. To trochę jak MVC, jeśli uważasz, że warstwa środkowa, API, warstwa jest równoważna Twojemu modelowi, tylko model nie jest prostym opakowaniem dla bazy danych, jest bogatszy i może zrobić znacznie więcej (np. Agregować dane z 2 źródeł danych, publikować -przetwarzaj dane w celu dopasowania do API, buforuj dane itp.):

gbjbaanb
źródło
2
Czy to prawda z architektonicznego punktu widzenia astronauta? Rozumiem twój drugi i trzeci akapit z punktu widzenia usługi, ale mówimy o GetUser, CreateUser, IsUserLoggedIn i setkach małych funkcji, które wcześniej były pojedynczymi wierszami kodu przekształcanymi w wywołania API.
NibblyPig,
12
Wyobraź sobie, że piszesz go jako stronę internetową - wszystkie te małe funkcje nie mogą być tak interaktywne, jak sobie wyobrażasz, więc będziesz musiał pobrać dane i buforować je lokalnie podczas tworzenia strony (lub przekazać je jako potencjalnie przestarzałe dane do klient, odpowiednio do systemu). W większości przypadków musisz zmienić swój projekt z „reagować na żądanie” na „przewidywać z góry”, ale większość twojego systemu będzie wykonywać wywołania API. Zaprojektuj swój interfejs API, aby był mniej szczegółowy i bardziej skoncentrowany na danych, więc IsUserLoggedOn nie musi być wywołaniem API, wystarczy „GetUserDetails” tylko raz, aby następnie sprawdzić lokalnie.
gbjbaanb
5
Zastosowaliśmy tę metodę w moim ostatnim miejscu pracy i zadziałała cudownie. Naszym głównym produktem była aplikacja internetowa, ale udało nam się stworzyć aplikację komputerową, a nawet arkusze Excela, które mogłyby uzyskać dostęp do tych samych usług internetowych, co nasza aplikacja internetowa dla wszystkich swoich danych, a dodatkowo udostępnić usługi naszym klientom, aby mogli program przeciwko nim.
Kik,
2
Oto kolejna zaleta: możesz udostępnić backend API klientom swojej witryny. Zrobiliśmy to w naszej firmie, a niektórzy klienci dużej firmy programistycznej (po wypróbowaniu backendu na naszym hoście) zapłacili za samodzielne zapakowanie backendu jako samodzielnego produktu. W zależności od produktu niektórzy klienci są mniej zainteresowani okleiną frontendową, a bardziej zainteresowani tym, co faktycznie robi Twój produkt - backendem. To kolejny produkt do sprzedania.
Reid,
2
Ułatwia to także korzystanie z tej samej logiki z usługi internetowej. Jedna z tych rzeczy, które nasze zespoły zawsze myślą, że nigdy nie będziemy musieli robić ... Ułatwia także testowanie jednostek.
ps2goat
87

Nie można uniknąć budowy interfejsu API . Nawet jeśli zbudujesz „tylko stronę internetową”, nadal będzie ona musiała w jakiś sposób pobierać dane z backendu. Jednak zdecydujesz się to zrobić, to jest de facto Twój interfejs API.

Wiedząc o tym, prawdziwym pytaniem nie jest to, czy zbudować interfejs API, ale jak go zbudować . Możesz to zrobić w locie jako rzecz ad hoc - i rzeczywiście wiele stron internetowych jest budowanych właśnie w ten sposób - lub możesz zaprojektować ją ostrożnie, aby była użyteczna w innych kontekstach. W tym kontekście staje się całkiem jasne, że twój kolega ma rację: najpierw powinieneś zrobić interfejs API, a następnie zbudować na nim swoją witrynę.

Niemniej jednak, jak zauważyłeś, wiąże się to z pewnymi obawami. Aby je rozwiązać:

To zbyt abstrakcyjne, żeby uruchomić backend z API. Próbujesz uczynić go zbyt elastycznym, co sprawi, że będzie to nieporządny bałagan.

To zależy od tego, jak to robisz. Jak zauważa George Pólya w swoim doskonałym tekście Jak go rozwiązać , często „bardziej ogólny problem może być łatwiejszy do rozwiązania”. Nazywa się to Paradoksem Wynalazcy . W przypadku programowania często działa to poprzez oddzielenie problemów: twój backend nie musi już zajmować się formatem danych, które wprowadza i usuwa, więc jego kod może być znacznie prostszy. Analizatory składni i renderery danych nie muszą się już martwić o to, co dzieje się z tworzonymi przez nich danymi, więc one także mogą być prostsze. Wszystko działa, dzieląc kod na łatwiejsze do zarządzania części.

Wszystkie rzeczy wbudowane w MVC wydają się bezużyteczne, takie jak role i uwierzytelnianie. Na przykład atrybuty i bezpieczeństwo [Autoryzuj]; będziesz musiał rzucić własne.

Przyznaję, że bardzo trudno mi współczuć z ludźmi, którzy odmawiają nauki swoich narzędzi. To, że nie rozumiesz ich użycia, nie oznacza, że ​​są bezużyteczne, a na pewno nie oznacza, że ​​powinieneś rzucić własne . Wręcz przeciwnie; nie powinieneś kręcić własnymi narzędziami, dopóki nie zrozumiesz alternatyw, aby mieć pewność, że rozwiążą te same problemy, które robią (nawet jeśli tylko na własne sposoby).

Weźmy na przykład Linusa Torvaldsa , który jest najbardziej znany z pisania Linuksa , ale także z git : teraz jednego z najpopularniejszych systemów kontroli wersji na świecie. Jednym z czynników napędzających jego projekt był głęboki sprzeciw wobec Subversion (kolejny niezwykle popularny VCS i prawdopodobnie najpopularniejszy w czasie pisania git); postanowił wziąć wszystko, co mógł Subversion i w miarę możliwości rozwiązać te problemy w inny sposób. Aby to zrobić, musiał sam stać się ekspertem w dziedzinie Subversion , tak aby mógł zrozumieć te same problematyczne dziedziny i przyjąć inne podejście.

Lub w trakcie uczenia się swoich narzędzi może się okazać, że są one użyteczne w obecnej postaci i nie trzeba ich wymieniać.

Wszystkie wywołania interfejsu API będą wymagać dołączenia informacji o bezpieczeństwie, a będziesz musiał opracować system tokenów i tak dalej.

Tak. To jest takie, jakie powinno być.

Będziesz musiał napisać pełne wywołania API dla każdej funkcji, jaką Twój program kiedykolwiek wykona. Prawie każda metoda, którą chcesz wdrożyć, będzie wymagała uruchomienia interfejsu API. Pobierz / zaktualizuj / usuń dla każdego użytkownika oraz wariant dla każdej innej operacji, np. Zaktualizuj nazwę użytkownika, dodaj użytkownika do grupy itp. Itd., A każda z nich będzie odrębnym wywołaniem API.

Niekoniecznie. To tutaj wkraczają architektury takie jak REST . Identyfikujesz zasoby, z którymi współpracuje Twoja aplikacja, i operacje, które mają sens, aby zastosować je do tych zasobów, a następnie wdrażasz je, nie martwiąc się tak bardzo o inne .

Tracisz wszelkiego rodzaju narzędzia, takie jak interfejsy i klasy abstrakcyjne, jeśli chodzi o interfejsy API. Rzeczy takie jak WCF mają bardzo słabe wsparcie dla interfejsów.

Wręcz przeciwnie, interfejsy stają się znacznie ważniejsze, gdy używasz interfejsu API, nie mniej . Pojawiają się w reprezentacjach, w które je renderujesz. Większość ludzi obecnie określa format oparty na JSON , ale możesz użyć dowolnego formatu, o ile dobrze go określisz. Renderujesz dane wyjściowe swoich wywołań do tego formatu na zapleczu i analizujesz je w dowolny sposób (prawdopodobnie ten sam obiekt) na interfejsie użytkownika. Koszty ogólne są małe, a wzrost elastyczności jest ogromny.

Masz metodę, która tworzy użytkownika lub wykonuje jakieś zadanie. Jeśli chcesz utworzyć 50 użytkowników, możesz po prostu zadzwonić do niego 50 razy. Gdy zdecydujesz się zastosować tę metodę jako interfejs API, lokalny serwer może połączyć się z nią nazwanymi potokami i nie ma problemu - twój klient pulpitu też może go trafić, ale nagle twoje masowe tworzenie użytkowników będzie wymagało 50-krotnego udoskonalenia interfejsu API nieźle. Musisz więc stworzyć metodę zbiorczą, ale tak naprawdę tworzysz ją tylko dla klientów stacjonarnych. W ten sposób musisz a) zmodyfikować interfejs API w oparciu o to, co się z nim integruje, i nie możesz po prostu bezpośrednio z nim zintegrować, b) wykonać o wiele więcej pracy, aby utworzyć dodatkową funkcję.

Tworzenie zbiorczej wersji istniejącej metody nie jest czymś, co nazwałbym „dużo więcej pracy”. Jeśli nie martwisz się o atomowość, metoda zbiorcza może być niewiele więcej niż bardzo cienką nakładką na oryginał.

YAGNI . O ile nie planujesz specjalnie napisać dwóch identycznie działających aplikacji, na przykład jednej aplikacji internetowej i jednej aplikacji Windows, jest to ogromna ilość dodatkowych prac programistycznych.

Nie, YANI (już tego potrzebujesz). Naszkicowałem to jak wyżej. Jedyne pytanie dotyczy tego, ile pracy włożono w projekt.

Debugowanie jest znacznie trudniejsze, gdy nie można przejść od końca do końca.

Dlaczego nie byłbyś w stanie przejść od końca do końca?

Ale przede wszystkim, możliwość badania danych w tę iz powrotem w łatwo rozpoznawalnym formacie, który wycina wszystkie cruft wyświetlacza, sprawia, że ​​debugowanie jest łatwiejsze , a nie trudniejsze.

Wiele niezależnych operacji, które będą wymagały wielu ruchów w przód iw tył, na przykład jakiś kod może uzyskać bieżącego użytkownika, sprawdzić, czy użytkownik jest w roli administratora, uzyskać firmę, do której należy użytkownik, uzyskać listę innych członków, wysłać im wszystkich email. Wymagałoby to wielu wywołań interfejsu API lub napisania niestandardowej metody dla konkretnego zadania, które chcesz, a jedyną korzyścią tej metody byłaby szybkość, ale wadą byłoby to, że byłaby nieelastyczna.

REST rozwiązuje to, pracując na kompletnych obiektach ( zasobach , aby użyć terminów teorii REST), a nie na indywidualnych właściwościach obiektów . Aby zaktualizować nazwę użytkownika, UZYSKASZ obiekt użytkownika, zmień jego nazwę i odłóż użytkownika z powrotem. Możesz wprowadzić inne zmiany w tym samym czasie, gdy zmieniasz także nazwę użytkownika. Bardziej ogólny problem staje się łatwiejszy do rozwiązania, ponieważ można wyeliminować wszystkie te indywidualne wezwania do aktualizacji indywidualnych właściwości obiektu: wystarczy go załadować i zapisać.

Pod pewnymi względami nie różni się to od architektur RISC po stronie sprzętowej. Jedną z kluczowych różnic między RISC i CISC (jego poprzednikiem) jest to, że architektury CISC zwykle zawierają wiele instrukcji, które działają bezpośrednio na pamięci, podczas gdy architektury RISC zwykle działają w rejestrach: w architekturze czysto RISC jedynymi operacjami na pamięci są LOAD (skopiuj coś z pamięci do rejestru) i STORE (pobierz wartość z rejestru i umieść w pamięci).

Można by pomyśleć, że oznaczałoby to przeniesienie o wiele więcej podróży z rejestrów do pamięci, co spowolniłoby pracę maszyny. Ale w praktyce często zdarza się coś przeciwnego: procesor (klient) wykonuje więcej pracy między podróżami do pamięci (serwera) i stąd pochodzi przyspieszenie.

Krótko mówiąc: twój kolega ma rację. To jest odpowiednie rozwiązanie. W zamian za trochę pracy z góry znacznie uprości kod Twojej witryny i umożliwi lepszą integrację z innymi stronami internetowymi i aplikacjami. To jest cena, którą warto zapłacić.

Dalsza lektura:

  1. Projektowanie interfejsu API REST - modelowanie zasobów
The Spooniest
źródło
7
Nawet te mają de facto pewnego rodzaju interfejsy API. Mają tendencję do powodowania, że ​​wielu innych programistów blednie z przerażenia, ale mimo to są interfejsami API; tylko niezbyt dobrze zaprojektowane.
Spooniest
7
To sprawia, że ​​naprawdę słaby interfejs API: tak słaby, że wiele osób nawet nie uważa go za interfejs API. Ale wciąż definiuje sposób, w jaki frontend współdziała z backendem, jakkolwiek może to być prymitywne. Myślenie o tym jak o API pomaga uświadomić sobie wagę robienia tego dobrze.
Spooniest
1
Myślę, że Linus zrobił git, ponieważ społeczność Linuksa zbuntowała się przeciwko użyciu komercyjnego Bitkeeper DVCS, który był używany dla jądra.
gbjbaanb
2
Twoje pierwsze zdanie rozwiewa całe moje zamieszanie. Termin API skojarzyłem z usługą internetową i to jest główny powód, dla którego byłem tak zdezorientowany.
NibblyPig
4
@IanNewson: istnieje sposób na połączenie z kodem, nazywa się http. Może mieć wiele nieistotnych wymagań i zwracać wiele nieistotnych danych, ale to czyni go kiepskim API.
jmoreno
63

Wiem, że mikrousług są teraz wściekłe, ale nie zawsze są tego warte. Tak, celem jest luźno powiązany kod. Ale nie powinno to odbywać się kosztem bardziej bolesnego cyklu rozwojowego.

Dobrym środkiem byłoby stworzenie osobnego projektu danych w swoim rozwiązaniu. Projekt danych byłby biblioteką klasy .NET. Twój projekt ASP.NET MVC doda następnie odwołanie do biblioteki danych, a wszystkie modele zostaną pobrane z projektu danych. Potem, gdy nadszedł czas na stworzenie aplikacji komputerowej lub mobilnej, możesz odwoływać się do tego samego kodu. Może więc nie być oficjalnym API, ale będzie działać jako jeden. Jeśli chcesz, aby był dostępny jako interfejs API, możesz utworzyć prosty projekt internetowy, który działa jak opakowanie projektu danych.

Microsoft promuje tę koncepcję, którą nazywają przenośnymi bibliotekami klas .

fotijr
źródło
13
Musiałem utrzymać projekt, w którym logika została umieszczona w warstwie interfejsu użytkownika, wywołując te same wspólne struktury danych. Z tego powodu musiałem naprawić jeden błąd trzydzieści razy („jeśli będziemy musieli ponownie użyć tej samej logiki, skopiujemy i wkleimy! Nie potrzeba interfejsu API”). Gdyby istniała warstwa logiczna (teraz jest), wystarczyłaby tylko jedna poprawka.
SJuan76
1
Ta odpowiedź, oprócz zawinięcia tej biblioteki we własny pakiet NuGet i hostowania własnego kanału / serwera pakietu NuGet, jest również dobrym rozwiązaniem. Nie musisz martwić się o wybredne sieci i możesz sprawić, by wszystkie połączenia były lokalne dla wątku (a zatem i szybciej), a ponadto wprowadzenie odpowiedniej wersji biblioteki klasowej za pomocą NuGet zapewnia innym zespołom elastyczność podczas aktualizacji.
Greg Burghardt
34

Nie, nie powinieneś . Jeśli nie masz natychmiastowych planów tworzenia alternatywnych nakładek (takich jak aplikacje mobilne lub stacjonarne lub osobna aplikacja internetowa), które uzyskują dostęp do tego samego zaplecza, nie powinieneś wprowadzać warstwy usług internetowych. YAGNI .

Luźne sprzężenie jest zawsze pożądane (wraz z wysoką kohezją), ale jest to zasada projektowania i nie oznacza, że ​​musisz fizycznie rozdzielać obiekty na różnych serwerach! Źle zaprojektowany interfejs API usługi może powodować ścisłe połączenie między serwerami, więc posiadanie interfejsu API nie gwarantuje luźnego łączenia.

Jeśli w przyszłości pojawi się potrzeba interfejsu API usługi, zawsze można go wprowadzić w tym momencie. Tak długo, jak będziesz utrzymywać swój kod ładnie warstwowo (dostęp do danych i logika biznesowa odseparowane od logiki interfejsu użytkownika), nie będzie trudniej wprowadzić go później niż jest teraz. A wynikowy projekt będzie znacznie lepszy, jeśli zostanie zaprojektowany w celu spełnienia rzeczywistych wymagań.


Uwaga: Zakładam, że pytanie brzmi, czy należy utworzyć interfejs API usługi sieci Web, czy nie. Pytanie tylko mówi API, ale API może również oznaczać interfejs biblioteki, a wtedy oczywiście każda warstwa będzie miała API z definicji. Konkluzja jest taka, że ​​logika biznesowa i warstwy dostępu do danych powinny być wyraźnie oddzielone od logiki interfejsu użytkownika na poziomie projektu, ale nie powinieneś wprowadzać warstwy usługi internetowej, jeśli jej nie potrzebujesz.

JacquesB
źródło
8
Źle zaprojektowane wszystko nie jest dobre. Budowanie interfejsu API nie wymaga więcej czasu i jest bardziej przyszłościowe. Zdolność przystosowania się do zmian jest dziś niezbędna, lepiej zbuduj silną bazę, aby zaspokoić wszelkie potrzeby, o których nawet nie wiesz, ale które mogą przyjść wcześniej, niż myślisz ...
Laurent S.,
9
@Bartdude: Wprowadzenie niepotrzebnej złożoności ze względu na „zabezpieczenie przyszłości” na przyszłość, która nie nadejdzie, jest po prostu marnowaniem zasobów.
JacquesB
6
@Bartdude dodanie interfejsu API to zdecydowanie więcej czasu. Nie mam pojęcia, jak według ciebie możesz twierdzić inaczej.
Ian Newson
13
interfejs API „nie powinieneś wprowadzać warstwy usługi internetowej”! = usługa internetowa. Jeżeli masz swoją logikę biznesową za pośrednictwem interfejsu API, możesz narazić tego interfejsu jako serwis WWW w pewnym momencie. Nie jest to jednak z góry wymóg.
Celos
2
@JacquesB: ... więc naprawdę nie rozwijasz funkcji, jeśli nie jesteś pewien, czy będziesz ich potrzebować. Właśnie to rozumiem z YAGNI. Jednak architektura nie jest cechą, a złe wybory architektoniczne mogą (i najprawdopodobniej doprowadzą) do nieszczęśliwej porażki. Po raz kolejny zakładam, że ta dyskusja może się nawet zdarzyć, co czasem nie jest tak z powodów budżetowych, czasu do wprowadzenia na rynek, zasobów lub braku wiedzy ... Myślę, że możemy całkowicie zgodzić się w tej sprawie, chociaż Rozumiem twój punkt widzenia, ponieważ często rozmawiałem ze sobą ^ _ ^
Laurent S.
29

Moja firma ma taką aplikację zbudowaną w ten sposób. Początkowo zlecono nam zbudowanie zaplecza z interfejsem API dla interfejsu, który tworzył inny programista. Gdy drugi programista nie mógł opracować tego interfejsu, zlecono nam również jego budowę. Chociaż takie podejście ma zdecydowanie zalety, ma ogromną wadę: koszt. Początkowa kompilacja będzie znacznie droższa, a bieżąca konserwacja będzie droższa, ze względu na więcej kodu do utrzymania i konieczność wdrożenia dwóch oddzielnych systemów. Ze względu na dodatkowe koszty, zawsze powinna to być decyzja biznesowa, a nie podstępna dla deweloperów.

Aby to przedstawić, oszacowałbym, że projekt, o którym wspomniałem powyżej, kosztował o 20% więcej dzięki temu podejściu. Nie opisujesz rodzaju projektu, nad którym pracujesz, dla jakiej firmy pracujesz, ale jeśli dopiero zaczynasz budować swój produkt, ten dodatkowy koszt może być różnicą między wysyłką kilku dodatkowych funkcji, które składają się na Twój produkt. sukces.

Innym powodem, dla którego nie, przynajmniej nie ogólnie, jest to, że jeśli lub kiedy zdecydujesz się utworzyć ten drugi interfejs, rzadko występuje mapowanie funkcjonalności jeden do jednego. Na przykład, jeśli tworzysz aplikację mobilną, ma ona zwykle mniej funkcji. Oznacza to, że niektóre metody interfejsu API nigdy nie będą ponownie używane. Dlatego kompromisem z kolegą może być wybór między najważniejszymi / najważniejszymi połączeniami i dodanie ich do interfejsu API oraz stosowanie bardziej tradycyjnych metod do wszystkiego innego.

Inną kwestią do rozważenia jest to, że twój kolega mówi, że nie będziesz w stanie ponownie wykorzystać istniejącego kodu, co nie jest prawdą, jeśli masz rozłąkę z logiką biznesową. Wystarczy utworzyć cienkie opakowanie usługi internetowej wokół wewnętrznych interfejsów API, co nie jest szczególnie dużym zadaniem. Naiwnością byłoby sądzić, że i tak można by użyć warstwy usługi internetowej do innego interfejsu bez żadnych zmian.

Ian Newson
źródło
22

To zależy od rodzaju aplikacji i rodzaju rynku, na którym jesteś.

Takie podejście wiąże się z kompromisami i korzyściami. Nie jest jednoznaczna odpowiedź, że jeden sposób jest lepszy od drugiego.

Porozmawiam z własnego doświadczenia. To ja zdecydowałem się zabrać bazę kodu, nad którą pracuję w tym kierunku, w 2007 roku. Baza ta jest teraz około miliona wierszy kodu, z czego połowa to kod serwera ukryty za ogromną ilością usług internetowych Interfejsy API, druga połowa to flotylla klientów, natywny komputer stacjonarny, sieć komputerowa, telefon komórkowy, integracja zaplecza itp. Ta decyzja nie była bez wad, ale z perspektywy 20/20 mogę powiedzieć, że zrobiłbym to jeszcze raz . Pozwól mi wskazać niektóre z kompromisów.

Korzyści

  • Elastyczność. Niezależnie od tego, czy jest to prośba o zbudowanie aplikacji mobilnej w celu zwiększenia wygody korzystania z pulpitu, czy prośba o integrację z zapleczem SAP, wszystko staje się łatwiejsze, gdy masz już interfejs API do wywołania. Gdy otrzymasz wystarczającą liczbę tych żądań, organicznie rozwiniesz się w kierunku interfejsu API, a jedynym pytaniem jest, czy ma przed sobą standardową usługę internetową, czy też jest to wewnętrzny interfejs API, w którym usługi sieciowe są dostosowane.

  • Skalowalność (zespołu). W naszym przypadku mamy wiele różnych grup programistów budujących na tym API. Mamy nawet dedykowane zespoły API, które rozmawiają z różnymi grupami, podsumowują potrzeby i konstruują z niego uniwersalny interfejs API. Doszło do tego, że nawet nie powiedziano nam już, że ludzie budują rzeczy na API, a nie każdy, kto to robi, działa dla naszej firmy.

  • Bezpieczeństwo. Wyraźny podział na niebezpieczne i bezpieczne części bazy kodu pomaga w zrozumieniu bezpieczeństwa. Błędne połączenie interfejsu użytkownika i kodu zaplecza powoduje zamieszanie.

Kompromisy

  • Elastyczność. Musisz wykonać pracę, aby „poprawnie” wbudować coś w interfejs API. Nie można szybko uruchomić zapytania DB z poziomu kodu interfejsu użytkownika, aby rozwiązać konkretny problem. Ponadto interfejsy API, które są rzeczywiście wielokrotnego użytku, muszą uwzględniać tak wiele przypadków użycia, że ​​szybkie rozwiązanie jest zwykle niewłaściwym rozwiązaniem. Interfejs API staje się mniej elastyczny w zakresie ewolucji, zwłaszcza, że ​​istnieje już tyle kodu klienta (z tego powodu przechodzimy na wersję API).

  • Początkowa prędkość rozwoju. Opracowywanie interfejsu API jest wolniejsze, bez cienia wątpliwości. Odzyskujesz go tylko wtedy, gdy masz wystarczającą liczbę klientów zbudowanych na interfejsie API. Ale potem okazuje się, że potrzebujesz 3 różnych implementacji klienckich, zanim interfejs API ewoluuje i będzie wystarczająco ogólny. Stwierdziliśmy, że większość naszych początkowych projektów API była błędna i musieliśmy zdecydowanie zmienić nasze wytyczne dotyczące tworzenia usług internetowych.

Czerwone śledzie

Wspomniałeś o kilku z nich. W praktyce nie mają one znaczenia.

  • Abstrakcja. Interfejs API staje się na tyle abstrakcyjny, że obejmuje wszystkie przypadki użycia, które musi obsługiwać Twój produkt, i nie więcej. Nawet bez usług internetowych będziesz mieć wewnętrzny interfejs API, który to robi, lub będziesz mieć dużo zduplikowanego kodu. Wolę abstrakcję niż powielanie.

  • Porzucenie stosu MVC po stronie serwera. Obecnie prawie każdy system będzie po chwili potrzebował aplikacji mobilnej. Gdy następnie zbudujesz usługi sieciowe dostosowane do tej aplikacji mobilnej, będziesz musiał dowiedzieć się, jak przeprowadzić uwierzytelnianie i autoryzację w kontekście interfejsu API. W rzeczywistości jest to mniej pracy, gdy masz tylko jeden sposób, aby to zrobić w swoich usługach internetowych.

  • Operacje masowe. Zwykle rozwiązywane przez utworzenie zbiorczego interfejsu API, który uruchamia zadanie zaplecza i zwraca identyfikator zadania do zapytania o status. To nie jest taka wielka sprawa.

  • Debugowanie Odkryłem, że ogólnie łatwiej było rozwiązać problem z systemem. Nadal możesz ustawiać punkty przerwania zarówno w kodzie front-end, jak i back-end, więc w praktyce nie jest to trudniejsze do przejścia, a ty zyskujesz możliwość budowania automatycznych testów API i instrumentowania API do monitorowania systemów produkcyjnych.

  • Wiele niezależnych operacji. To kwestia tego, jak projektujesz rzeczy. Jeśli nalegasz na posiadanie czystego CRUD API, to tak, będziesz cierpieć z powodu tego problemu. Ale mając niektóre API CQRS do rozszerzenia, co jest zwykle dobrym pomysłem, a jeśli upewniłeś się, że masz wewnętrzny interfejs API, dla którego usługi są front-endem, możesz łatwo ponownie użyć tego wewnętrznego interfejsu API do budowy usług dla tych konkretnych scenariusz.

W podsumowaniu

W systemie, który jest używany w dość różnych kontekstach, API ewoluuje naturalnie, ponieważ jest to najłatwiejszy sposób zaspokojenia wszystkich potrzeb. Ale z pewnością dzieje się tak w przypadku YAGNI. Istnieją kompromisy i nie ma to sensu, dopóki nie ma sensu. Najważniejsze jest, aby nie być dogmatycznym i zachować otwarty umysł na różne podejścia do architektury w celu zaspokojenia zmieniających się potrzeb produktu.

Joeri Sebrechts
źródło
Interesująca lektura, czy możesz wyjaśnić, co popełniłeś źle podczas projektowania interfejsu API i czego się nauczyłeś?
aaaaaaaaaaaa
3
Trzy główne błędy to: (1) dopasowanie interfejsu do potrzeb głównego interfejsu użytkownika, (2) budowanie stanu dla wielu żądań za pomocą sesji (stopniowo stajemy się bez sesji) i (3) wspieranie tylko użycia wygenerowanego db id jako identyfikator, w którym kod konfigurowany przez użytkownika jest często lepszym identyfikatorem (w przypadku integracji z systemami zewnętrznymi zazwyczaj chcą przesłać identyfikatory do naszego systemu w celu późniejszego użycia w interfejsach API zamiast na odwrót). Te trzy elementy wraz ze słabą dokumentacją i niepomocnymi komunikatami o błędach uniemożliwiły użycie interfejsu API bez pomocy.
Joeri Sebrechts
10

Twój kolega opisuje architekturę zorientowaną na usługi. Może to być niezwykle skalowalny, testowalny i rozsądny sposób kodowania, ale tak naprawdę zależy od tego, co tworzysz.

Istnieje kilka znaczących korzyści dla SOA, które spróbuję wyliczyć:

Skalowalność

Ponieważ twój backend jest oddzielony, twój front staje się tylko serią szablonów, a nawet płaskimi plikami. Flatfiles są niezwykle szybkie i tanie w obsłudze z dowolnego CDN. Można je zminimalizować i wstępnie skompilować do statycznego kodu HTML, a następnie zapełnić danymi po stronie klienta.

Twój interfejs API musi pozostać spójny, ale można go zamienić na szybszą technologię bez zrywania stosu, jeśli przerośniesz istniejącą technologię. Możesz go przerobić na przykład w Go. Możesz go odbudować fragmentarycznie i rozłożyć obciążenie na serwery. Dopóki interfejs pozostaje taki sam, technologia jest abstrakcyjna.

Testowalność

MVC zwykle zaczyna się od wyczyszczenia, ale w praktyce kontrolery rzadko koncentrują się na jednym zasobie. Im więcej rzeczy robią metody kontrolera, tym stają się mniej testowalne.

Interfejs API omija ten problem. Każde wywołanie API pobiera zasób i obsługuje go. Czysty i testowalny.

Gwarantowany podział problemów

Twój przód i tył są w pełni rozwiedzeni. Możesz przekazać interfejs innym programistom lub projektantom. To MVC przeniesione na inny poziom. Jestem pewien, że nie chcesz rezygnować z MVC. SOA to MVC, ale bardziej.

Wady

Są oczywiście pewne wady. Monolit jest często szybszy. Może to być to, do czego jesteś przyzwyczajony. Może lepiej pasować do twojego stosu. Twoje narzędzia mogą być zoptymalizowane do tworzenia monolitu.

Żadne z tych nie jest moim zdaniem szczególnie dobrym powodem i możesz rozważyć ponowne wprowadzenie narzędzi, jeśli dotyczą ciebie.

superluminarny
źródło
To jak dotąd najbardziej klarowna odpowiedź.
Tony Ennis
7

Jest tu wiele dobrych odpowiedzi, więc dodam swoje doświadczenie związane z implementacją.

Tak robię rzeczy:

  • Utwórz warstwę dostępu do bazy danych, która obsługuje wszystkie operacje DB / tylko interakcje (zwykle ręczny SQL jest używany do szybkości i kontroli, bez ORM) . Wstaw, zaktualizuj, usuń, wybierz ...
  • Utwórz interface( virtual class), który udostępnia / wymusza funkcje API, których potrzebuję. Po wdrożeniu będą korzystać z wysoce wyspecjalizowanych funkcji DBAL w celu osiągnięcia wyników. Pomaga mi również egzekwować interfejs API na poziomie kompilatora, dlatego upewniam się, że implementacja API Server + ma wbudowane wszystkie funkcje.
  • Utwórz drugą warstwę, która implementuje interfejs (jest to rzeczywisty interfejs API) i egzekwuje ograniczenia bezpieczeństwa. Tutaj możesz również wchodzić w interakcje z zewnętrznymi interfejsami API.
  • Witryna będzie korzystać z drugiej warstwy bezpośrednio (w celu zwiększenia wydajności) bez korzystania z interfejsu API dostępnego zdalnie (takiego jak SOAP, JSON) .
  • Autonomiczny serwer jest kompilacją, która implementuje interfejs i udostępnia drugą warstwę jako rzeczywisty interfejs API dostępny zdalnie zewnętrznym klientom stacjonarnym / mobilnym (dostęp poza witryną) . Wszystko, co robi, to dekodowanie żądań i kodowanie odpowiedzi oraz zarządzanie / rozłączanie klientów. Obsługuje również funkcje wypychania, aby masowo powiadamiać klientów o zdarzeniach generowanych przez innych połączonych partnerów (funkcjonalność, której zwykle nie wymaga strona internetowa) .

Tak więc technicznie API jest drugą warstwą. Używasz go bezpośrednio z witryną i udostępniasz go klientom zdalnym za pośrednictwem serwera. Kod jest ponownie wykorzystywany i żadna część kodu wielokrotnego użytku nie jest nigdy wbudowana. (żyj i giń zgodnie z tą zasadą i wszystko jest niesamowite) Pomaga w utrzymaniu, testowaniu ... wszystkiego.

Nigdy nie łączysz strony internetowej z serwerem API dla komputerów stacjonarnych / urządzeń mobilnych (chyba że twoja strona to AJAX i działa na JSON) . Ale jeśli witryna wyświetla dynamiczną treść w znacznikach, przejście przez pośredni interfejs API obniży Twoją wydajność. Strona musi być szybka! Zdalny dostęp do klienta może być nieco wolniejszy.

PS : Tak, konserwacja jest nieco bardziej złożona, ponieważ więcej kół współpracuje, ale na dłuższą metę jest łatwiej. Jeśli więc projekt ma trwać przez chwilę i jest nieco złożony, zawsze należy mieć interfejs API. Znacznie łatwiej jest też przetestować każdą warstwę osobno.

CodeAngry
źródło
Brzmi to całkiem fajnie i ma sens, szczególnie stawiając interfejs na funkcje typu API. Spróbuję tego ustawienia następnym razem, gdy utworzę projekt!
NibblyPig,
6

Kwestią sporną nie jest to, czy powinieneś używać interfejsu API, ale to, czym tak naprawdę jest „interfejs API”. Jedyną alternatywą dla używania zaprojektowanego API jest użycie API, które jest przypadkowym bałaganem kodu. Piszesz, że API czyni „zbyt elastycznym”, co z kolei czyni zarządzanie niemożliwym do zarządzania. Wskazuje to na całkowite i dogłębne niezrozumienie, czym jest interfejs API. Jeśli to nieporozumienie nie zostanie podzielone między tobą a twoim współpracownikiem, zmarnujesz dużo czasu, kłóciąc się o zupełnie inne rzeczy.

Nie używając dobrze zdefiniowanego interfejsu API, możesz robić, co chcesz. Z definicji jest to najbardziej elastyczna opcja. Ponadto z definicji „rób co chcesz” jest nadal interfejsem API. Tylko praca z API jest usunięcie elastyczność. Po usunięciu elastyczności dobry interfejs API zachęca użytkownika do robienia podobnych rzeczy w podobny sposób.

Oczywiście zły interfejs API może zapewniać zbyt dużą lub zbyt małą elastyczność, a nawet oba jednocześnie. Naprawdę źle zaprojektowany interfejs API może zabić projekt nawet szybciej niż podejście „wszystko idzie”. Jednak najlepszą praktyką jest po prostu posiadanie kompetentnych programistów, którzy opracowują i rozwijają interfejs API wraz z aplikacją.

Przykład

• Wiele niezależnych operacji, które będą wymagały wielu ruchów w przód iw tył, na przykład jakiś kod może uzyskać bieżącego użytkownika, sprawdzić, czy użytkownik pełni rolę administratora, uzyskać firmę, do której należy użytkownik, uzyskać listę innych członków, wysłać ich cały e-mail. Wymagałoby to wielu wywołań interfejsu API lub napisania niestandardowej metody dla konkretnego zadania, które chcesz, a jedyną korzyścią tej metody byłaby szybkość, ale wadą byłoby to, że byłaby nieelastyczna.

Liczba wywołań interfejsu API, które wymagałyby tego w przypadku przyzwoitego interfejsu API, prawdopodobnie wynosiłaby 1. Tak, jest nieelastyczny, ale dlaczego miałby być elastyczny?

Piotr
źródło
4

Powiedział, że nasz kod jest zbyt ściśle powiązany. Na przykład, jeśli chcielibyśmy mieć również aplikację komputerową, nie moglibyśmy użyć naszego istniejącego kodu.

A ty? Jeśli nie, to jest to dość nieistotne stwierdzenie.

Powiedziałbym, że jeśli zamierzasz zbudować nową aplikację w 2015 roku, poważnie przyjrzyj się czemuś z interfejsem użytkownika, który obejmuje API, a nie strony HTML generowane przez serwer. Istnieją wyraźne koszty, ale także wyraźne korzyści.

Ale jeśli masz istniejącą witrynę bez konkretnych planów posiadania kilku różnych interfejsów (o ile mi wiadomo), to jego komentarze są nieistotne.

RemcoGerlich
źródło
4

Krótka wersja: Twój kontroler skutecznie API bez względu na wszystko; chociaż ASP.NET może to zaciemniać.

Dłuższa wersja:

Pomyśl o podstawowej aplikacji internetowej MVC, która zawiera informacje o piwie i opcjonalnie ją sprzedaje. Jak wyglądają trasy?

/sign_in
/sign_out
/beer
/beer/{beer_name}
/order
/order/{order_number}

W normalnej aplikacji internetowej istnieje prawdopodobnie kilka pomocniczych tras, takich jak:

/beer/new
/beer/{beer_name}/edit
/beer/{beer_name}/delete
/order/new
/order/{order_number}/edit
/order/{order_number}/delete

W interfejsie API sieci Web nie są one wymagane, ponieważ wywodzą się z metody HTTP.

Biorąc pod uwagę powyższą symetrię, myślę, że jest to dość przekonujący przypadek, że twój interfejs API i kontroler są tak blisko, że równie dobrze mogą być tym samym.

Po kilku kopaniach ustaliłem, że może to być stan rzeczy w zależności od używanej wersji programu ASP.NET. Starsze MVC 5, a wcześniej brakowało konwencji i interfejsu, aby solidnie ujednolicić obie implementacje. W starszych wersjach aplikacja sieci Web zwraca wypełnia widok, a interfejs API daje odpowiedź HttpResponse. W obu przypadkach generują one dokładnie taką samą odpowiedź semantycznie.

Jeśli używasz MVC 6, otrzymujesz oba w zunifikowanej klasie kontrolerów, która może być inteligentna w kwestii tego, co zwraca. Nie znalazłem żadnego dobrego przykładowego kodu ASP dla tego modelu, ale znalazłem trochę kodu Rails z tym samym wzorem. Rozważ ten kontroler pod kątem „polubień” z projektu Diaspora . Każda metoda kontrolera ma trasy zdefiniowane tutaj przez „ zaradną konwencję” , które odpowiadają LCRUD w interfejsie API.

Jeśli jednak czytasz implementacje, każda z nich może odpowiadać na HTML, Mobile HTML lub JSON. W połączeniu z konwencją wyszukiwania widoków całkowicie ujednolica aplikację sieci Web i interfejs API sieci Web. Zauważysz również, że nie wszystkie metody faktycznie zapewniają każdą odpowiedź (co ma sens, ponieważ interfejs użytkownika może wymagać metod, których interfejs API nie będzie, i odwrotnie).

Jest to niedopasowanie impedancji, ponieważ ASP.NET zorientował się w tym wszystkim późno, podczas gdy Railsy przyjęły tę symetrię od pewnego czasu i to bardzo wyraźnie.

Spekulacja:

Twój współpracownik jest prawdopodobnie zarówno dobry, jak i zły, w zależności od używanej wersji ASP. W starej wersji MVC różnica między interfejsem API a aplikacją prawdopodobnie sprawiła, że ​​„najlepszą praktyką” było zbudowanie interfejsu API z góry, ponieważ model programu ASP.NET tak naprawdę nie pozwalał na dobre ponowne użycie kodu.

W przypadku nowszego bardziej sensowne jest użycie zunifikowanego kodu, ponieważ łatwiej było ponownie używać kodu z klasą bazową zunifikowanego kontrolera.

W obu przypadkach kontroler jest faktycznie interfejsem API.

Jayson
źródło
Na to pytanie odpowiedziano na śmierć, ale nie sądzę, aby pozostałe odpowiedzi były tak jasne. „Nie można uniknąć budowy interfejsu API”. odpowiedź była niemal natychmiastowa, a zaakceptowana odpowiedź tańczyła wokół tego samego problemu; ale oba nie odnosiły się do ASP w sposób, który według mnie doprowadził do sedna sprawy.
Jayson
Im więcej odpowiedzi tym lepiej, pomagają uzyskać dobre zrozumienie tego, co sądzą o tym inni ludzie.
NibblyPig,
2

Kiedy rozpocząłem swoją karierę w 2006 roku, ten typ architektury cieszył się popularnością w świecie .NET. Pracowałem nad 3 oddzielnymi projektami stworzonymi w połowie 2000 roku z usługą internetową między warstwą logiki biznesowej a nakładką internetową. Oczywiście w dzisiejszych czasach usługi sieciowe były SOAP, ale nadal mają tę samą architekturę. Domniemanymi korzyściami była możliwość przełączania frontonu lub backendu, a nawet rozwijania programu komputerowego. Ostatecznie YAGNI okazało się prawdą. Nigdy tego nie widziałem. Przez cały ten czas widziałem tylko koszt podziału projektu w ten sposób. Skończyło się nawet na wyrywaniu serwisu internetowego z jednego z projektów (zajęło mi to pół roku, aby usunąć go krok po kroku, wykonując inne czynności) i cały zespół był szczęśliwy. Od tego czasu nigdy nie próbowałem tego podejścia i nie zrobię tego, chyba że podam konkretny powód. 5 lat doświadczenia w wypróbowywaniu tej architektury nauczyło mnie, że nie będę jej potrzebować i żadna liczba ekspertów, którzy twierdzą, że jest odwrotnie, nie przekonuje mnie, że tak będzie. Może to zrobić tylko projekt, w którym go potrzebuję.

Teraz jednak staram się stworzyć warstwę między logiką biznesową a kontrolerami / prezenterami. Na przykład mam warstwę usług, nigdy nie ujawniam kwerend, używam interfejsów dla wszystkich moich usług i wstrzykuję je do kontrolerów z IoC. Jeśli kiedykolwiek będę potrzebować usługi internetowej w mojej architekturze, będę mógł wprowadzić ją za rozsądną cenę. Po prostu nie chcę z góry opłacać tych kosztów.

Również podoba mi się pomysł mikrousług, ale rozumiem, że mikrousługi to raczej moduły pionowe niż poziome. Na przykład, jeśli budujesz na Facebooku, funkcja czatu będzie oddzielną usługą wdrażaną osobno na własnych serwerach itp. Zachęcam do tego typu niezależnych usług.

Stilgar
źródło
2

Czy skorzystają z niego osoby trzecie? Tak, powinieneś .

Planujesz użyć go ponownie w niedalekiej przyszłości? Tak, powinieneś.
Będziesz stroną trzecią , posiadając udokumentowane - lub udokumentowane - lub użyteczne przez strony trzecie API zapewni solidne możliwości ponownego wykorzystania i modułowość.

Spieszysz się? Nie, nie powinieneś.
Refaktoryzacja jest później łatwiejsza i szybsza niż większość metodologii i nauczycieli przewiduje i mówi. Ważniejsze jest, aby mieć coś, co działa (nawet przy złym projekcie wewnętrznym, ponieważ może i zostanie zrefaktoryzowane), niż nie mieć niczego. (ale z niesamowitym projektem wewnętrznym, wohoo)

Interfejs może nigdy nie ujrzeć światła dziennego z powodów? Tak, powinieneś .
Dodałem ten powód, ponieważ cóż, bardzo mi się to przytrafiło.
Przynajmniej pozostaję z moimi komponentami do ponownego wykorzystania i redystrybucji itp.

ZJR
źródło
1

Tutaj są dobre odpowiedzi. Publikuję to jako częściową odpowiedź; być może byłoby lepiej jako komentarz. Jednak umieszczanie tego samego komentarza w wielu postach nie jest dobre.

Nie można twierdzić, że YAGNI jest powodem, dla którego nie utworzono interfejsu API.

Interfejs API jest naturalnym i logicznym punktem końcowym testowania. Dlatego od samego początku istnieją dwie aplikacje korzystające z interfejsu API: interfejs użytkownika i pakiet testowy. Jeden jest przeznaczony dla ludzi, drugi dla maszyn. Z konieczności są różne. Testowanie zachowania front-end jest znacznie innym zadaniem niż testowanie zachowania back-end. Zatem techniki i prawdopodobnie narzędzia są zupełnie inne. Interfejs API pozwala na użycie najlepszego narzędzia do zadania. Co więcej, dzięki separacji zapewnianej przez API, testerzy frontonu nie muszą testować funkcjonalności back-endu.

Interfejs API pomaga również trzymać kodery front-end z dala od problemów kodera back-end i odwrotnie. Są to bardzo różne umiejętności w naszej firmie; API pozwala nam skupić się tam, gdzie jesteśmy najsilniejsi.

Tony Ennis
źródło