Jak napisać zestaw funkcji, które można wywoływać z (prawie) dowolnego języka programowania?

33

Chciałbym znaleźć sposób na napisanie interfejsu API, do którego można uzyskać dostęp z dowolnego innego języka programowania za pośrednictwem powiązań językowych (lub innego frameworka). Czy można to zrobić? Jeśli tak, to który język programowania byłby najbardziej odpowiedni do napisania API „międzyjęzykowego”? Moim celem jest stworzenie jednego zestawu funkcji, do których będę mieć dostęp z dowolnego języka programowania, z którym pracuję, aby nie musiałem ręcznie ponownie pisać całego API w każdym języku.

Anderson Green
źródło
4
Jeśli chcesz po prostu powiedzieć „wspieramy WSZYSTKO” ze względów marketingowych, możesz po prostu napisać niskopoziomową bibliotekę DLL lub bibliotekę współdzieloną w C. Jeśli chcesz, żeby ktoś powiedział na przykład Java, mógłbyś użyć Twojego oprogramowania lepiej zapewnić interfejs Java.
mjfgates,
1
Mówisz „(prawie) dowolne”, które języki byś wykluczył w tym celu? Lub które są dla Ciebie najważniejsze?
funkybro,
22
Serwis internetowy? Możesz napisać niektóre funkcje na przykład w php. Prawie każdy język może łączyć się ze stronami internetowymi, podawać argumenty i czytać wyniki.
Pieter B,
7
+1, ponieważ to interesujące pytanie - ale twoje pytanie poprawiłoby się, mówiąc, dlaczego chcesz to zrobić. Jakie są Twoje cele?
TarkaDaal,
@PieterB => odpowiedz.
Konrad Rudolph,

Odpowiedzi:

44

Masz kilka opcji:

  1. Utwórz interfejs HTTP, prawie wszystko może mówić HTTP, dzięki czemu dostaniesz wiele języków.

  2. Utwórz coś, co można połączyć w środowisko wykonawcze języka, będzie to raczej czasochłonne, ponieważ będziesz musiał znaleźć sposób na połączenie go z wieloma różnymi językami.

Zachary K.
źródło
Jaki konkretnie rodzaj interfejsu HTTP masz na myśli?
Anderson Green,
@AndersonGreen To nie powinno mieć znaczenia (ponieważ każdy język, który może otworzyć gniazdo sieciowe, może mówić HTTP), ale REST jest użytecznym pseudo-standardem.
Przywróć Monikę
7
REST + JSON byłby rozsądnym rozwiązaniem
David Hayes,
Zgadzam się również, że używanie HTTP do komunikacji pozwala praktycznie każdemu językowi na interakcję z funkcjami twojej aplikacji.
Tylko boliwijski Tutaj
30

Myślę, że C lub C ++ byłyby najbardziej odpowiednie dla twojego celu. Możesz użyć SWIG (Simplified Wrapper and Interface Generator) do generowania powiązań językowych z API C lub C ++.

SWIG to narzędzie do tworzenia oprogramowania, które łączy programy napisane w C i C ++ z różnymi językami programowania wysokiego poziomu. SWIG jest używany z różnymi typami języków docelowych, w tym popularnymi językami skryptowymi, takimi jak Perl, PHP, Python, Tcl i Ruby. Lista obsługiwanych językówzawiera także języki nieskrypty, takie jak C #, Common Lisp (CLISP, Allegro CL, CFFI, UFFI), język D, Go, Java, w tym Android, Lua, Modula-3, OCAML, Octave i R. Również kilka interpretowanych i skompilowanych schematów implementacje (Guile, MzScheme / Racket, Chicken) są obsługiwane. SWIG jest najczęściej używany do tworzenia interpretowanych lub skompilowanych środowisk programistycznych wysokiego poziomu, interfejsów użytkownika oraz jako narzędzie do testowania i prototypowania oprogramowania C / C ++. SWIG jest zwykle używany do analizowania interfejsów C / C ++ i generowania „kodu kleju” wymaganego do wywołania powyższych języków docelowych do kodu C / C ++. SWIG może również eksportować swoje drzewo parsowania w postaci wyrażeń XML i Lisp. SWIG jest wolnym oprogramowaniem, a kod generowany przez SWIG jest zgodny zarówno z projektami komercyjnymi, jak i niekomercyjnymi ...

LKM
źródło
32
C ++ byłby okropnym wyborem. Jest z tym wiele problemów: zależność od biblioteki wykonawczej, nieokreślony ABI (szczególnie mangling) itp. Generowanie powiązań z nagłówków C ++ jest zbyt trudne. SWIG jest dość ograniczoną rzeczą. Zobacz całą skomplikowaną infrastrukturę wokół, powiedzmy, powiązań Pyttona Qt.
SK-logic
14
@ SK-logic: Niezupełnie. C potrzebuje biblioteki uruchomieniowej, podobnie jak C ++. ABI można kontrolować w C ++, dzięki extern "C"czemu jest on kompatybilny z C na zewnątrz. Stąd masz wewnętrzne zalety C ++ (większe bezpieczeństwo typu, biblioteki), ale zewnętrzne zalety C (de facto standard ABI)
MSalters
3
@ SK-logic Nieokreślony ABI to po prostu rozwiązany problem, patrz SWIG, Boost.Python i wiele innych powiązań językowych.
Konrad Rudolph,
3
@MSalters nie zapomnieć o wyjątki i ich ogólnego braku workiness ponad granicami bibliotecznych
sehe
3
-1 dla sugestii C ++. C jest łatwe, C ++ sprawia, że ​​rzeczy stają się niepotrzebnie trudne.
Ernest Friedman-Hill
23

Istnieją prawie 2 sposoby:

  • API C. Praktycznie każdy język, jaki kiedykolwiek istniał, ładuje bibliotekę C i wywołuje jej funkcje. To, jak to zrobisz, zależy od języka źródłowego.
  • pewnego rodzaju mechanizm RPC. Może to być interfejs API REST działający przez HTTP lub interfejs binarny działający przez gniazdo. O ile nie wybierzesz mechanizmu o najniższym wspólnym mianowniku (np. Gnieździe), ryzykujesz brak procedur dostępu klienta (np. Niektóre języki nie mają odpowiednich klientów SOAP do wywołania interfejsu API zaimplementowanego przy użyciu SOAP lub występują problemy z interoperacyjnością). Trzymaj się najprostszego, interfejsu HTTP / REST lub gniazda. Zaletą gniazd jest to, że nie potrzebują serwera HTTP, aby udostępnić interfejs klientom, i mogą łatwiej działać na tym samym serwerze co klient z lepszą wydajnością.

Praca wymagana dla tych zmian zależy od używanego systemu, na przykład interfejs gniazda będzie działał, ale biblioteki po stronie klienta mają tendencję do bardziej niskiego poziomu w porównaniu do bibliotek http.

Możesz spróbować znaleźć bibliotekę sieciową, która obsługuje wszystkie języki, których chcesz używać, i zaimplementować interfejs API pod kątem tej biblioteki - np. Użycie ZeroMQ daje dużą elastyczność, więc możesz napisać swój interfejs API za pomocą interfejsów ZeroMQ i wówczas każdy język, który chce wywołać interfejs API, musi do tego celu użyć biblioteki klienta ZeroMQ. Wybierz bibliotekę, która obsługuje szeroką gamę języków i pozwala na komunikację zarówno w trakcie, jak i poza procesem w celu uzyskania najlepszej wydajności.

gbjbaanb
źródło
Jakie kroki powinienem podjąć, jeśli chcę napisać API również w wielu językach? (W moim przypadku tymi językami byłyby Javascript, C ++ i Java.)
Anderson Green
Czy powinienem po prostu napisać 3 oddzielne interfejsy API RESTful dla każdego z języków?
Anderson Green
Piszemy natywne opakowanie w każdym z tych języków, które obsługuje ładowanie i wywoływanie podstawowej biblioteki dll. Lub napisz to w C ++ i użyj SWIG, aby to zrobić za Ciebie. Jeśli używasz interfejsu API REST, to samo dotyczy, albo napisz pojedynczy interfejs API, a następnie 3 opakowania, ale jeśli piszesz interfejs API REST, każdy język będzie mógł wywoływać interfejs API REST bezpośrednio - nie przejmuj się z owijarką.
gbjbaanb
Czy dll (dynamicznie linkowana biblioteka) byłby kompatybilny z dowolną platformą inną niż Windows? Potrzebuję tutaj kompatybilności między platformami.
Anderson Green,
nie, musisz go ponownie skompilować dla innych platform. Na przykład Linux używa .so zamiast .dll. Potrzebna jest tylko prosta rekompilacja, brak (lub bardzo niewielkie) zmiany kodu.
gbjbaanb
12

Jeśli wydajność i opóźnienia połączeń nie stanowią problemu, zastanów się nad zapewnieniem kompleksowego interfejsu wiersza poleceń (prawdopodobnie używając na nim języka skryptowego). ImageMagick może być dobrym przykładem takiego „API”. Innym dobrym przykładem jest zestaw narzędzi Tk.

Logika SK
źródło
Który język skryptowy i / lub język programowania poleciłbyś do stworzenia interfejsu funkcji obcych w wierszu poleceń? Czy znalazłeś też jakieś konkretne przykłady takich interfejsów?
Anderson Green
@AndersonGreen, dowolny język z przyzwoitym metaprogramowaniem jest odpowiedni do tego celu. Np. Scheme, MetaLua, różne inne możliwe do osadzenia Lisps, Tcl. Możesz łatwo wdrożyć własny język poleceń. Wiele systemów CAD / CAE działa w ten sposób. Wspomniany już Tk jest kolejnym typowym przykładem.
SK-logic
Czy w celu użycia interfejsu wiersza poleceń w ten sposób otrzymujesz dane wyjściowe konsoli dla konkretnego polecenia (np. W whoamisystemie Ubuntu, aby uzyskać nazwę użytkownika), czy masz coś innego na myśli?
Anderson Green,
@AndersonGreen, piping stdin i stdout powinny wystarczyć w większości przypadków.
SK-logic,
5

Przez API, co dokładnie masz na myśli?

Na wielu platformach możesz połączyć się z biblioteką DLL lub podobną konstrukcją, ale czy musiałbyś zostać ponownie skompilowany dla konkretnego natywnego celu (Intel / ARM) lub endianness nadal się kwalifikuje? Konkretny interfejs binarny może nadal mieć problemy z niektórymi językami z powodu problemów z typami danych lub konstrukcji (wskaźniki próbujące powrócić do języków, które nie obsługują ich dobrze), dlatego należy również rozważyć projekt samego interfejsu API, aby nie aby wykluczyć niektóre języki lub sprawić, by korzystanie z tych języków było uciążliwe.

Coś przenośnego, takiego jak C i interfejs oparty na binarnych punktach końcowych w bibliotece DLL, może być w porządku i ogólnie wywoływać na większości platform i z większości języków, ale może być konieczne skompilowanie go w inny sposób i / lub zaoferowanie w różnych smakach lub połączenie z różnymi bibliotekami statycznymi.

Wydaje mi się, że wybór języka, w którym piszesz swoją bibliotekę lub usługę, lub cokolwiek innego, z definicji nie jest nieodłączny od pytania, dopóki nie podasz więcej informacji na temat platformy / usługi udostępnianej przez API. Jeśli można założyć, że stos sieci jest dostępny, a wydajność na poziomie wywołania funkcji bezpośrednio połączonej nie jest wymagana, interfejs API może być oparty na protokole HTTP z pewnym rodzajem podkładki, aby język klienta był przejrzysty.

Myślę, że ogólnie to pytanie jest zbyt szerokie, aby było przydatne w prawdziwym świecie, ponieważ nie wskazałeś, jaki rodzaj interfejsu API może być odpowiedni, biorąc pod uwagę rodzaj oferowanej usługi.

Cade Roux
źródło
2

Aby dodać do powyższych odpowiedzi, które sugerują użycie mechanizmu RPC. Możesz użyć Apache Thrift. ( Http://thrift.apache.org/ ). Jest to w zasadzie framework RPC.

Zgodnie z wiki Thrift:

Platforma programowa Apache Thrift do skalowalnego rozwoju usług międzyjęzykowych łączy stos oprogramowania z silnikiem generowania kodu w celu tworzenia usług, które działają wydajnie i bezproblemowo między C ++, Java, Python, PHP, Ruby, Erlang, Perl, Haskell, C #, Kakao, JavaScript, Node.js, Smalltalk, OCaml i Delphi i inne języki

gt5050
źródło
Jak można wywoływać funkcje zagraniczne za pomocą Apache Thrift?
Anderson Green
0

Niech dowolny język wypisze plik tekstowy z funkcją do wywołania z parametrami do przekazania. Niech twoja aplikacja „dogaduję się z kimkolwiek” ogląda katalog, a kiedy zobaczy proces-call.txt, niech zacznie działać. Brak serwerów lub protokołów sieciowych; nawet metoda języka innego niż komputer może inicjować funkcje. Nawet osoba może po prostu utworzyć plik tekstowy.

Treść może wyglądać następująco:

Call-method:  fdisk()
Params:  (string) "/root", (string) "write-back-file-expected.txt"

;) możesz jednak czekać wiecznie, aby uzyskać odpowiedź. Wystarczy przesunąć kilka bajtów do drugiego procesu, ale jestem pewien, że to nie jest cała specyfikacja.

Pareshkumar
źródło
Wydaje się to zbyt skomplikowane, gdy można mieć po prostu interfejs wiersza poleceń + stdin / stdout.
Przywróć Monikę
1
Jeszcze lepsze połączenie może ++ 1, Brendan. Nigdy nie widziałem tego w akcji, ale kiedyś ludzie wybijali dziury w karcie, aby przenieść bajty.
Pareshkumar,
4
To odpowiedź żartu, prawda? Nie robimy tego tutaj.
Ernest Friedman-Hill
Cóż, fdisk i / root to żart, ale ja byłem zaangażowany jako platforma badawczo-rozwojowa (programista i analityk) przez ponad 5 lat, aby stworzyć platformę, która przyniosła dobre wyniki w dziesiątkach milionów dolarów. Wydobywa miliony fizycznych przesyłek (nie pdf i e-mail) dla klienta (z przetwarzaniem plików w setkach MB na element) przy użyciu tego rodzaju metody REST. Mieliśmy duży system triolgy - SAP-MS Office-PLC Drivewrs-PDF Workflow - wszystko to do siebie nawzajem współpracowało i dobrze współpracowało ze zwykłymi plikami tekstowymi UTF-8 i zamkiem błyskawicznym z zamkiem błyskawicznym z zamkiem błyskawicznym, i brak narzutu HTTP bs.
Pareshkumar
Mogę zadać pytanie? Dlaczego nikt nie uważa, że ​​JSON to żart? Czym różni się to, co polecam? Moglibyśmy / moglibyśmy użyć Jsona, ale nie było go w 2003 roku. XML jest zbyt gruby, ale wtedy był to smak miesiąca, który nie był najbardziej praktyczny i najprostszy.
Pareshkumar
0

OpenGL jest dobrym przykładem tego, co opisujesz - jest to interfejs API napisany w C, zaprojektowany w sposób łatwy do pisania powiązań w innych językach

  1. Biblioteki C można wywoływać z większości języków programowania (zwykle jako skompilowane rozszerzenia lub rzeczy takie jak ctypesbiblioteka PyPy itp.)

  2. Wszystkie funkcje przyjmują proste typy danych jako argumenty (logiczne, całkowite, zmiennoprzecinkowe, stałe, tablice), ponieważ funkcje przyjmujące wskaźniki mogą być niewygodne w tłumaczeniu na niektóre języki

  3. Posiadanie własnych liczbowych typów danych, które określają precyzję i znakowość (podczas gdy int floatitp. Mogą się różnić)

Wynikowy interfejs API niekoniecznie jest najłatwiejszym w użyciu interfejsem API C, który można napisać, jeśli jest skierowany tylko do użytkowników C. Oznacza to jednak, że funkcje mogą być niemal bezpośrednio wystawione na inny język (np. Dokumenty PyOpenGL wymieniają różnice, z których większość jest dość minimalna)

Oprócz tego pełnego API możesz pisać wokół niego więcej „przyjaznych dla programistów” opakowań (frameworki gier itp.)

dbr
źródło