Uwaga
Dostęp do tej strony wymaga autoryzacji. Może spróbować zalogować się lub zmienić katalogi.
Dostęp do tej strony wymaga autoryzacji. Możesz spróbować zmienić katalogi.
Implementacja internetowego interfejsu API RESTful to internetowy interfejs API, który wykorzystuje zasady architektury Representational State Transfer (REST) w celu osiągnięcia bezstanowego, luźno powiązanego interfejsu między klientem a usługą. Interfejs API webowy, który jest RESTful, obsługuje standardowy protokół HTTP do wykonywania operacji na zasobach i zwracania reprezentacji tych zasobów, które zawierają hipermedialne linki oraz kody stanu operacji HTTP.
Internetowy interfejs API RESTful powinien być zgodny z następującymi zasadami:
Niezależność platformy, co oznacza, że klienci mogą wywoływać internetowy interfejs API niezależnie od wewnętrznej implementacji. Aby uzyskać niezależność od platformy, internetowy interfejs API używa protokołu HTTP jako standardowego protokołu, udostępnia przejrzystą dokumentację i obsługuje znany format wymiany danych, taki jak JSON lub XML.
Luźne sprzęganie, co oznacza, że klient i usługa internetowa mogą ewoluować niezależnie. Klient nie musi znać wewnętrznej implementacji usługi internetowej, a usługa internetowa nie musi znać wewnętrznej implementacji klienta. Aby osiągnąć luźne sprzężenie w internetowym interfejsie API RESTful, użyj tylko standardowych protokołów i zaimplementuj mechanizm, który umożliwia klientowi i usłudze internetowej uzgadnianie formatu danych do wymiany.
W tym artykule opisano najlepsze rozwiązania dotyczące projektowania internetowych interfejsów API RESTful. Obejmuje również typowe wzorce projektowe i zagadnienia dotyczące tworzenia internetowych interfejsów API, które są łatwe do zrozumienia, elastyczne i łatwe w utrzymaniu.
Pojęcia dotyczące projektowania internetowego interfejsu API RESTful
Aby zaimplementować internetowy interfejs API RESTful, należy zrozumieć następujące pojęcia.
Uniform Resource Identifier (URI): Interfejsy API REST są projektowane wokół zasobów, które są dowolnym rodzajem obiektu, danych lub usługi, do których klient ma dostęp. Każdy zasób jest reprezentowany przez identyfikator URI, który jednoznacznie identyfikuje ten zasób. Na przykład identyfikator URI dla określonego zamówienia klienta może być:
https://api.contoso.com/orders/1
Reprezentacja zasobu definiuje sposób kodowania zasobu identyfikowanego przez jego identyfikator URI i transportowany za pośrednictwem protokołu HTTP w określonym formacie, takim jak XML lub JSON. Klienci, którzy chcą pobrać określony zasób, muszą używać identyfikatora URI zasobu w żądaniu do interfejsu API. Interfejs API zwraca reprezentację danych zasobu określonych przez URI. Na przykład klient może wysłać żądanie GET do identyfikatora
https://api.contoso.com/orders/1
URI, aby otrzymać następującą treść JSON:{"orderId":1,"orderValue":99.9,"productId":1,"quantity":1}
Jednolity interfejs to sposób, w jaki interfejsy API RESTful zapewniają luźne powiązanie między implementacjami klienta i usługi. W przypadku interfejsów API REST, które są oparte na protokole HTTP, jednolity interfejs obejmuje używanie standardowych czasowników HTTP do wykonywania operacji, takich jak
GET
,POST
,PUT
,PATCH
iDELETE
na zasobach.Model żądań bezstanowych: Interfejsy API RESTful używają modelu żądania bezstanowego, co oznacza, że żądania HTTP są niezależne i mogą występować w dowolnej kolejności. Z tego powodu przechowywanie przejściowych informacji o stanie między żądaniami nie jest możliwe. Jedynym miejscem, w którym są przechowywane informacje, są same zasoby, a każde żądanie powinno być operacją niepodzielną. Model żądań bezstanowych obsługuje wysoką skalowalność, ponieważ nie musi zachowywać powiązań między klientami a konkretnymi serwerami. Jednak model bezstanowy może również ograniczyć skalowalność ze względu na wyzwania związane ze skalowalnością magazynu zaplecza usługi internetowej. Aby uzyskać więcej informacji na temat strategii skalowania w poziomie dla magazynu danych, zobacz Partycjonowanie danych.
Hipermedia — linki: Interfejsy API REST mogą być sterowane za pomocą linków hipermedia, które znajdują się w każdej reprezentacji zasobu. Na przykład poniższy blok kodu przedstawia reprezentację JSON zamówienia. Zawiera on linki umożliwiające pobranie lub zaktualizowanie klienta skojarzonego z zamówieniem.
{ "orderID":3, "productID":2, "quantity":4, "orderValue":16.60, "links": [ {"rel":"product","href":"https://api.contoso.com/customers/3", "action":"GET" }, {"rel":"product","href":"https://api.contoso.com/customers/3", "action":"PUT" } ] }
Określanie identyfikatorów URI zasobów w RESTful web API
Internetowy interfejs API RESTful jest zorganizowany wokół zasobów. Aby zorganizować projekt interfejsu API w oparciu o zasoby, zdefiniuj identyfikatory URI zasobów mapujące na jednostki biznesowe. Jeśli to możliwe, opieraj identyfikatory URI zasobów na rzeczownikach (zasobu), a nie czasownikach (operacje na zasobie).
Na przykład w systemie handlu elektronicznego główne jednostki biznesowe mogą być klientami i zamówieniami. Aby utworzyć zamówienie, klient wysyła informacje o zamówieniu w żądaniu HTTP POST do adresu URI zasobu. Odpowiedź HTTP na żądanie wskazuje, czy tworzenie zamówienia zakończyło się pomyślnie.
URI do tworzenia zasobu zamówienia może wyglądać następująco:
https://api.contoso.com/orders // Good
Unikaj używania czasowników w identyfikatorach URI do reprezentowania operacji. Na przykład następujący identyfikator URI nie jest zalecany:
https://api.contoso.com/create-order // Avoid
Jednostki są często grupowane w kolekcje, takie jak klienci lub zamówienia. Kolekcja jest oddzielnym zasobem od elementów wewnątrz kolekcji, więc powinna mieć własny identyfikator URI. Na przykład następujący identyfikator URI może reprezentować kolekcję zamówień:
https://api.contoso.com/orders
Kiedy klient pobierze kolekcję, może wysłać żądanie GET do identyfikatora URI każdego elementu. Na przykład, aby otrzymać informacje o określonym zamówieniu, klient wykonuje żądanie HTTP GET na URI https://api.contoso.com/orders/1
, aby otrzymać następującą treść JSON jako reprezentację zasobu danych zamówienia wewnętrznego.
{"orderId":1,"orderValue":99.9,"productId":1,"quantity":1}
Konwencje nazewnictwa identyfikatorów URI zasobów
Podczas projektowania internetowego interfejsu API RESTful ważne jest, aby używać poprawnych konwencji nazewnictwa i relacji dla zasobów:
Użyj rzeczowników dla nazw zasobów. Użyj nouns do reprezentowania zasobów. Na przykład użyj
/orders
zamiast/create-order
. Metody HTTP GET, POST, PUT, PATCH i DELETE już implikują akcję słowną.Użyj rzeczowników w liczbie mnogiej do nazywania identyfikatorów URI kolekcji. Ogólnie rzecz biorąc, pomaga używać rzeczowników w liczbie mnogiej dla identyfikatorów URI odwołujących się do kolekcji. Dobrą praktyką jest organizowanie identyfikatorów URI dla kolekcji i elementów w hierarchii. Na przykład
/customers
jest ścieżką do kolekcji klienta i/customers/5
jest ścieżką do klienta o identyfikatorze równym 5. Takie podejście pomaga zachować intuicyjność internetowego interfejsu API. Ponadto wiele struktur internetowego interfejsu API może kierować żądania na podstawie sparametryzowanych ścieżek identyfikatorów URI, dzięki czemu można zdefiniować trasę dla ścieżki/customers/{id}
.Rozważ relacje między różnymi typami zasobów i sposobem uwidocznienia tych skojarzeń. Na przykład element
/customers/5/orders
może reprezentować wszystkie zamówienia dla klienta 5. Możesz również skierować relację w innym kierunku, reprezentując związek między zamówieniem a klientem. W tym scenariuszu identyfikator URI może mieć wartość/orders/99/customer
. Jednak rozszerzenie tego modelu zbyt daleko może stać się kłopotliwe do wdrożenia. Lepszym rozwiązaniem jest dołączenie linków w treści komunikatu odpowiedzi HTTP, dzięki czemu klienci mogą łatwo uzyskiwać dostęp do powiązanych zasobów. "Użycie hiperłącza jako mechanizmu stanu aplikacji (HATEOAS) umożliwiającego nawigację do powiązanych zasobów" opisuje ten mechanizm bardziej szczegółowo.Zachowaj proste i elastyczne relacje. W bardziej złożonych systemach można pochylić się nad udostępnieniem identyfikatorów URI, które umożliwiają klientowi nawigowanie po kilku poziomach relacji, takich jak
/customers/1/orders/99/products
. Jednak ten poziom złożoności może być trudny do utrzymania i jest nieelastyczny, jeśli relacje między zasobami zmieniają się w przyszłości. Zamiast tego spróbuj zachować stosunkowo proste identyfikatory URI. Gdy aplikacja ma odwołanie do zasobu, powinno być możliwe użycie tego odwołania do znajdowania elementów powiązanych z tym zasobem. Powyższe zapytanie można zastąpić identyfikatorem URI/customers/1/orders
, aby znaleźć wszystkie zamówienia dla klienta 1, a następnie użyć polecenia/orders/99/products
, aby znaleźć produkty w tej kolejności.Wskazówka
Unikaj wymagania identyfikatorów URI zasobów, które są bardziej złożone niż kolekcja/element/kolekcja.
Unikaj dużej liczby małych zasobów. Wszystkie żądania internetowe nakładają obciążenie na serwer internetowy. Im więcej żądań, tym większe obciążenie. Internetowe interfejsy API, które ujawniają dużą liczbę małych zasobów, są nazywane gadatliwymi interfejsami internetowymi API. Spróbuj uniknąć tych interfejsów API, ponieważ wymagają one od aplikacji klienckiej wysyłania wielu żądań w celu znalezienia wszystkich danych, których potrzebuje. Zamiast tego należy rozważyć zdenormalizowanie danych i połączenie powiązanych informacji w większe zasoby, które można pobrać za pośrednictwem jednego żądania. Jednak nadal trzeba zrównoważyć to podejście względem obciążenia związanego z pobieraniem danych, których klient nie potrzebuje. Pobieranie dużych obiektów może zwiększyć opóźnienie żądania i zwiększyć koszty przepustowości. Aby uzyskać więcej informacji na temat tych antywzorców wydajności, zobacz także Chatty I/O i Nadmiarowe pobieranie.
Unikaj tworzenia interfejsów API, które dubluje wewnętrzną strukturę bazy danych. Celem rest jest modelowanie jednostek biznesowych i operacji, które aplikacja może wykonywać na tych jednostkach. Klient nie powinien być narażony na implementację wewnętrzną. Jeśli na przykład dane są przechowywane w relacyjnej bazie danych, internetowy interfejs API nie musi uwidaczniać każdej tabeli jako kolekcji zasobów. Takie podejście zwiększa obszar ataków i może spowodować wyciek danych. Zamiast tego należy traktować internetowy interfejs API jako abstrakcję bazy danych. W razie potrzeby wprowadź warstwę mapowania między bazą danych a internetowym interfejsem API. Ta warstwa zapewnia, że aplikacje klienckie są odizolowane od zmian w bazowym schemacie bazy danych.
Wskazówka
Mapowanie każdej operacji zaimplementowanej przez internetowy interfejs API na określony zasób może nie być możliwe. Te scenariusze niezwiązane ze źródłem można obsługiwać za pomocą żądań HTTP, które wywołują funkcję i zwracają wyniki jako komunikat odpowiedzi HTTP.
Na przykład internetowy interfejs API, który implementuje proste operacje kalkulatora, takie jak dodawanie i odejmowanie, może udostępniać identyfikatory URI, które uwidaczniają te operacje jako pseudo zasoby i używają ciągu zapytania do określenia wymaganych parametrów. Żądanie GET do adresu URI /add?operand1=99&operand2=1 zwraca komunikat odpowiedzi z treścią zawierającą wartość 100.
Należy jednak używać tych form identyfikatorów URI oszczędnie.
Definiowanie metod interfejsu API RESTful
Metody internetowego interfejsu API RESTful są zgodne z metodami żądań i typami multimediów zdefiniowanymi przez protokół HTTP. W tej sekcji opisano najbardziej typowe metody żądań i typy multimediów używane w internetowych interfejsach API RESTful.
Metody żądań HTTP
Protokół HTTP definiuje wiele metod żądań, które wskazują akcję, którą chcesz wykonać w zasobie. Najbardziej typowe metody używane w internetowych API RESTful to GET, POST, PUT, PATCH i DELETE. Każda metoda odpowiada określonej operacji. Podczas projektowania internetowego interfejsu API RESTful użyj tych metod w sposób zgodny z definicją protokołu, zasobem, do którego uzyskuje się dostęp, oraz wykonywaną akcją.
Należy pamiętać, że wpływ określonej metody żądania powinien zależeć od tego, czy zasób jest kolekcją, czy pojedynczym elementem. Poniższa tabela zawiera niektóre konwencje, których używa większość implementacji RESTful.
Ważne
W poniższej tabeli użyto przykładowej jednostki handlu elektronicznego customer
. Internetowy interfejs API nie musi implementować wszystkich metod żądania. Metody, które implementuje, zależą od konkretnego scenariusza.
zasób | POST | POBIERZ | POŁÓŻ | USUNĄĆ |
---|---|---|---|---|
/klienci | Tworzenie nowego klienta | Pobierz wszystkich klientów | Zbiorcza aktualizacja klientów | Usuń wszystkich klientów |
/klienci/1 | Błąd | Pobierz szczegóły klienta 1 | Zaktualizuj dane klienta 1, jeśli istnieje | Usuwanie klienta 1 |
/customers(klienci)/1/orders(zamówienia) | Tworzenie nowego zamówienia dla klienta 1 | Pobieranie wszystkich zamówień dla klienta 1 | Zbiorcza aktualizacja zamówień dla klienta 1 | Usuń wszystkie zamówienia dla klienta 1 |
Żądania GET
Żądanie GET pobiera reprezentację zasobu pod określonym Uniform Resource Identifier (URI). Treść komunikatu odpowiedzi zawiera szczegóły żądanego zasobu.
Żądanie GET powinno zwrócić jeden z następujących kodów stanu HTTP:
Kod stanu HTTP | Powód |
---|---|
200 (OK) | Metoda pomyślnie zwróciła zasób. |
204 (brak zawartości) | Treść odpowiedzi nie zawiera żadnej zawartości, na przykład gdy żądanie wyszukiwania nie zwraca żadnych dopasowań w odpowiedzi HTTP. |
404 (nie znaleziono) | Nie można odnaleźć żądanego zasobu. |
Żądania POST
Żądanie POST powinno utworzyć zasób. Serwer przypisuje identyfikator URI dla nowego zasobu i zwraca ten identyfikator URI do klienta.
Ważne
W przypadku żądań POST klient nie powinien próbować utworzyć własnego identyfikatora URI. Użytkownik powinien przesłać żądanie do URI kolekcji, a serwer powinien przypisać identyfikator URI nowemu zasobowi. Jeśli klient próbuje utworzyć własny identyfikator URI i wysyła żądanie POST do określonego identyfikatora URI, serwer zwraca kod stanu HTTP 400 (NIEPRAWIDŁOWE ŻĄDANIE), aby wskazać, że metoda nie jest obsługiwana.
W modelu RESTful żądania POST są używane do dodawania nowego zasobu do kolekcji, którą identyfikuje identyfikator URI. Jednak żądanie POST może być również używane do przesyłania danych do przetwarzania do istniejącego zasobu bez tworzenia nowego zasobu.
Żądanie POST powinno zwrócić jeden z następujących kodów stanu HTTP:
Kod stanu HTTP | Powód |
---|---|
200 (OK) | Metoda wykonała pewne przetwarzanie, ale nie tworzy nowego zasobu. Wynik operacji może zostać uwzględniony w treści odpowiedzi. |
201 (Utworzono) | Zasób został pomyślnie utworzony. Identyfikator URI nowego zasobu jest zawarty w nagłówku 'Location' odpowiedzi. Treść odpowiedzi zawiera reprezentację zasobu. |
204 (brak zawartości) | Treść odpowiedzi nie zawiera zawartości. |
400 (Nieprawidłowe żądanie) | Klient umieścił nieprawidłowe dane w żądaniu. Treść odpowiedzi może zawierać więcej informacji o błędzie lub odnośnik do URI, który dostarcza dodatkowych szczegółów. |
405 (Niedozwolona metoda) | Klient próbował wysłać żądanie POST do adresu URI, który nie obsługuje żądań POST. |
Żądanie PUT
Żądanie PUT powinno zaktualizować istniejący zasób, jeśli istnieje lub w niektórych przypadkach utworzyć nowy zasób, jeśli nie istnieje. Aby wysłać żądanie PUT:
- Klient określa identyfikator URI zasobu i zawiera treść żądania, która zawiera pełną reprezentację zasobu.
- Klient wysyła żądanie.
- Jeśli zasób o tym identyfikatorze URI już istnieje, zostanie on zastąpiony. W przeciwnym razie zostanie utworzony nowy zasób, jeśli trasa go obsługuje.
Metody PUT są stosowane do zasobów, które są poszczególnymi elementami, takimi jak określony klient, zamiast kolekcji. Serwer może obsługiwać aktualizacje, ale nie tworzyć za pośrednictwem funkcji PUT. To, czy można obsługiwać tworzenie za pośrednictwem funkcji PUT, zależy od tego, czy klient może znacząco i niezawodnie przypisać identyfikator URI do zasobu, zanim istnieje. Jeśli nie jest to możliwe, użyj funkcji POST, aby utworzyć zasoby i pozwolić serwerowi przypisać identyfikator URI. Następnie użyj funkcji PUT lub PATCH, aby zaktualizować identyfikator URI.
Ważne
Żądania PUT muszą być idempotentne, co oznacza, że przesyłanie tego samego żądania wielokrotnie powoduje, że ten sam zasób jest modyfikowany przy użyciu tych samych wartości. Jeśli klient ponownie wysyła żądanie PUT, wyniki powinny pozostać niezmienione. Z kolei żądania POST i PATCH nie mają gwarancji, że są idempotentne.
Żądanie PUT powinno zwrócić jeden z następujących kodów stanu HTTP:
Kod stanu HTTP | Powód |
---|---|
200 (OK) | Zasób został pomyślnie zaktualizowany. |
201 (Utworzono) | Zasób został pomyślnie utworzony. Treść odpowiedzi może zawierać reprezentację zasobu. |
204 (brak zawartości) | Zasób został pomyślnie zaktualizowany, ale treść odpowiedzi nie zawiera żadnej zawartości. |
409 (Konflikt) | Żądanie nie mogło zostać ukończone z powodu konfliktu z aktualnym stanem zasobu. |
Wskazówka
Rozważ zaimplementowanie zbiorczych operacji HTTP PUT, które mogą aktualizować wiele zasobów jednocześnie w kolekcji. Żądanie PUT powinno określać identyfikator URI kolekcji. Treść żądania powinna określać szczegóły zasobów, które mają zostać zmodyfikowane. Takie podejście może pomóc zmniejszyć liczbę rozmów i zwiększyć wydajność.
Żądania PATCH
Żądanie PATCH wykonuje częściową aktualizację istniejącego zasobu. Klient określa identyfikator URI zasobu. Treść żądania określa zestaw zmian, które mają być stosowane do zasobu. Ta metoda może być wydajniejsza niż użycie żądań PUT, ponieważ klient wysyła tylko zmiany, a nie całą reprezentację zasobu. Funkcja PATCH może również utworzyć nowy zasób, określając zestaw aktualizacji dla pustego lub zerowego zasobu, jeśli serwer obsługuje tę akcję.
W przypadku żądania PATCH klient wysyła zestaw aktualizacji do istniejącego zasobu w postaci dokumentu poprawki. Serwer przetwarza dokument poprawki w celu przeprowadzenia aktualizacji. Dokument poprawki określa tylko zestaw zmian, które mają być stosowane, zamiast opisywać cały zasób. Specyfikacja metody PATCH RFC 5789 nie definiuje określonego formatu dokumentów poprawek. Format musi być wywnioskowany z typu nośnika w żądaniu.
JSON to jeden z najbardziej typowych formatów danych dla internetowych interfejsów API. Dwa główne formaty poprawek oparte na formacie JSON to poprawka JSON i poprawka scalania JSON.
Poprawka scalania JSON jest prostsza niż poprawka JSON. Dokument poprawki ma taką samą strukturę jak oryginalny zasób JSON, ale zawiera tylko podzestaw pól, które powinny zostać zmienione lub dodane. Ponadto można usunąć pole, określając null
wartość pola w dokumencie poprawki. Ta specyfikacja oznacza, że poprawka scalania nie jest odpowiednia, jeśli oryginalny zasób może mieć jawne wartości null.
Załóżmy na przykład, że oryginalny zasób ma następującą reprezentację JSON:
{
"name":"gizmo",
"category":"widgets",
"color":"blue",
"price":10
}
Oto możliwa poprawka scalania JSON dla tego zasobu:
{
"price":12,
"color":null,
"size":"small"
}
Ta poprawka scalania informuje serwer, aby zaktualizować price
, usunąć color
, i dodać size
. Wartości dla name
i category
nie są modyfikowane. Aby uzyskać więcej informacji na temat poprawki scalania JSON, zobacz RFC 7396. Typ nośnika dla poprawki scalania JSON to application/merge-patch+json
.
Poprawka scalania nie jest odpowiednia, jeśli oryginalny zasób może zawierać jawne wartości null ze względu na specjalne znaczenie null
w dokumencie poprawki. Dokument poprawki nie określa również kolejności stosowania aktualizacji przez serwer. To, czy ta kolejność ma znaczenie, zależy od danych i domeny. Poprawka JSON zdefiniowana w dokumencie RFC 6902 jest bardziej elastyczna, ponieważ określa zmiany jako sekwencję operacji do zastosowania, w tym dodawanie, usuwanie, zastępowanie, kopiowanie i testowanie w celu zweryfikowania wartości. Typ nośnika dla poprawki JSON to application/json-patch+json
.
Żądanie PATCH powinno zwrócić jeden z następujących kodów stanu HTTP:
Kod stanu HTTP | Powód |
---|---|
200 (OK) | Zasób został pomyślnie zaktualizowany. |
400 (Nieprawidłowe żądanie) | Źle sformułowany dokument poprawkowy. |
409 (Konflikt) | Dokument poprawki jest prawidłowy, ale nie można zastosować zmian do zasobu w bieżącym stanie. |
415 (nieobsługiwany typ nośnika) | Format dokumentu poprawki nie jest obsługiwany. |
Żądania „DELETE”
Żądanie DELETE usuwa zasób pod określonym URI. Żądanie DELETE powinno zwrócić jeden z następujących kodów stanu HTTP:
Kod stanu HTTP | Powód |
---|---|
204 (BRAK ZAWARTOŚCI) | Zasób został pomyślnie usunięty. Proces został pomyślnie obsłużony, a treść odpowiedzi nie zawiera dalszych informacji. |
404 (NIE ZNALEZIONO) | Zasób nie istnieje. |
Typy MIME zasobów
Reprezentacja zasobu to sposób, w jaki zasób identyfikowany przez identyfikator URI jest kodowany i transportowany za pośrednictwem protokołu HTTP w określonym formacie, takim jak XML lub JSON. Klienci, którzy chcą pobrać określony zasób, muszą używać identyfikatora URI w żądaniu do interfejsu API. API odpowiada, zwracając reprezentację zasobu danych wskazanego przez URI.
W protokole HTTP formaty reprezentacji zasobów są określane przy użyciu typów multimediów, nazywanych również typami MIME. W przypadku danych niebinarnych większość internetowych interfejsów API obsługuje format JSON (typ nośnika = ) i prawdopodobnie XML (typ nośnika = application/json
application/xml
).
Nagłówek Content-Type w żądaniu lub odpowiedzi określa format reprezentacji zasobu. W poniższym przykładzie pokazano żądanie POST zawierające dane JSON:
POST https://api.contoso.com/orders
Content-Type: application/json; charset=utf-8
Content-Length: 57
{"Id":1,"Name":"Gizmo","Category":"Widgets","Price":1.99}
Jeśli serwer nie obsługuje typu nośnika, powinien zwrócić kod stanu HTTP 415 (nieobsługiwany typ nośnika).
Żądanie klienta może zawierać nagłówek Accept zawierający listę typów multimediów akceptowanych przez klienta z serwera w komunikacie odpowiedzi. Na przykład:
GET https://api.contoso.com/orders/2
Accept: application/json, application/xml
Jeśli serwer nie może być zgodny z żadnym z wymienionych typów nośników, powinien zwrócić kod stanu HTTP 406 (Nie do przyjęcia).
Implementowanie metod asynchronicznych
Czasami metoda POST, PUT, PATCH lub DELETE może wymagać przetwarzania, które zajmuje trochę czasu. Jeśli poczekasz na ukończenie przed wysłaniem odpowiedzi do klienta, może to spowodować niedopuszczalne opóźnienie. W tym scenariuszu rozważ utworzenie metody asynchronicznej. Metoda asynchroniczna powinna zwrócić kod stanu HTTP 202 (Zaakceptowane), aby wskazać, że żądanie zostało zaakceptowane do przetworzenia, ale jest niekompletne.
Uwidacznianie punktu końcowego zwracającego stan żądania asynchronicznego, aby klient mógł monitorować stan, sondując punkt końcowy stanu. Uwzględnij identyfikator URI punktu końcowego stanu w nagłówku Location odpowiedzi 202. Na przykład:
HTTP/1.1 202 Accepted
Location: /api/status/12345
Jeśli klient wysyła żądanie GET do tego punktu końcowego, odpowiedź powinna zawierać bieżący stan żądania. Opcjonalnie może zawierać szacowany czas ukończenia lub link umożliwiający anulowanie operacji.
HTTP/1.1 200 OK
Content-Type: application/json
{
"status":"In progress",
"link": { "rel":"cancel", "method":"delete", "href":"/api/status/12345" }
}
Jeśli operacja asynchroniczna tworzy nowy zasób, punkt końcowy stanu powinien zwrócić kod stanu 303 (Zobacz inne) po zakończeniu operacji. W odpowiedzi 303 dołącz nagłówek Lokalizacja, który określa identyfikator URI nowego zasobu.
HTTP/1.1 303 See Other
Location: /api/orders/12345
Aby uzyskać więcej informacji, zobacz Zapewnianie asynchronicznej obsługi długotrwałych żądań i wzorca asynchronicznego Request-Reply.
Implementowanie stronicowania i filtrowania danych
Aby zoptymalizować pobieranie danych i zmniejszyć rozmiar ładunku, zaimplementuj stronicowanie danych i filtrowanie oparte na zapytaniach w projekcie interfejsu API. Te techniki umożliwiają klientom zażądanie tylko potrzebnego podzestawu danych, co może poprawić wydajność i zmniejszyć użycie przepustowości.
Stronicowanie dzieli duże zestawy danych na mniejsze fragmenty, którymi można zarządzać. Użyj parametrów zapytania, takich jak
limit
, aby określić liczbę elementów do zwrócenia ioffset
określić punkt początkowy. Upewnij się również, że zapewniono znaczące wartości domyślne dlalimit
ioffset
, takie jaklimit=25
ioffset=0
. Na przykład:GET /orders?limit=25&offset=50
limit
: określa maksymalną liczbę elementów do zwrócenia.Wskazówka
Aby zapobiec atakom typu "odmowa usługi", rozważ nałożenie górnego limitu liczby zwracanych elementów. Na przykład, jeśli Twoja usługa ustawia
max-limit=25
, a klient żądalimit=1000
, Twoja usługa może zwrócić 25 elementów lub błąd HTTP BAD-REQUEST, w zależności od dokumentacji API.offset
: określa indeks początkowy danych.
Filtrowanie umożliwia klientom uściślenie zestawu danych przez zastosowanie warunków. Interfejs API może pozwalać klientowi na przekazanie filtru w łańcuchu zapytania URI.
GET /orders?minCost=100&status=shipped
-
minCost
: Filtruje zamówienia, które mają minimalny koszt 100. -
status
: Filtruje zamówienia, które mają określony stan.
-
Rozważ następujące najlepsze rozwiązania:
Sortowanie umożliwia klientom sortowanie danych przy użyciu parametru,
sort
takiego jaksort=price
.Ważne
Metoda sortowania może mieć negatywny wpływ na buforowanie, ponieważ parametry ciągu zapytania stanowią część identyfikatora zasobu, którego wiele implementacji pamięci podręcznej używa jako klucza do buforowanych danych.
Wybór pól dla projekcji zdefiniowanych przez klienta umożliwia klientom określanie tylko pól, których potrzebują przy użyciu parametru, takiego
fields
jakfields=id,name
. Na przykład można użyć parametru ciągu zapytania, który akceptuje rozdzielaną przecinkami listę pól, takich jak /orders?fields=ProductID,Quantity.
Interfejs API musi zweryfikować żądane pola, aby upewnić się, że klient może uzyskiwać do nich dostęp i nie uwidacznia pól, które nie są zwykle dostępne za pośrednictwem interfejsu API.
Wsparcie dla częściowych odpowiedzi
Niektóre zasoby zawierają duże pola binarne, takie jak pliki lub obrazy. Aby przezwyciężyć problemy spowodowane zawodnymi i sporadycznymi połączeniami oraz poprawić czas odpowiedzi, rozważ obsługę częściowego pobierania dużych zasobów binarnych.
Aby obsługiwać częściowe odpowiedzi, internetowy interfejs API powinien obsługiwać nagłówek Accept-Ranges dla żądań GET dla dużych zasobów. Ten nagłówek wskazuje, że operacja GET obsługuje częściowe żądania. Aplikacja kliencka może przesyłać żądania GET zwracające podzbiór zasobu określonego jako zakres bajtów.
Należy również rozważyć zaimplementowanie żądań HTTP HEAD dla tych zasobów. Żądanie HEAD jest podobne do żądania GET, z tą różnicą, że zwraca tylko nagłówki HTTP opisujące zasób z pustą treścią komunikatu. Aplikacja kliencka może wydać żądanie HEAD, aby określić, czy pobrać zasób przy użyciu częściowych żądań GET. Na przykład:
HEAD https://api.contoso.com/products/10?fields=productImage
Oto przykładowy komunikat odpowiedzi:
HTTP/1.1 200 OK
Accept-Ranges: bytes
Content-Type: image/jpeg
Content-Length: 4580
Nagłówek Content-Length zawiera całkowity rozmiar zasobu, a nagłówek Accept-Ranges wskazuje, że odpowiednia operacja GET obsługuje częściowe wyniki. Aplikacja kliencka może używać tych informacji do pobierania obrazu w mniejszych fragmentach. Pierwsze żądanie pobiera pierwsze 2500 bajtów przy użyciu nagłówka Range.
GET https://api.contoso.com/products/10?fields=productImage
Range: bytes=0-2499
Komunikat odpowiedzi wskazuje, że ta odpowiedź jest częściowa, zwracając kod stanu HTTP 206. Nagłówek Content-Length określa rzeczywistą liczbę bajtów zwracanych w treści komunikatu, a nie rozmiar zasobu. Nagłówek Content-Range wskazuje, która część zasobu jest zwracana (bajty 0–2499 z 4580):
HTTP/1.1 206 Partial Content
Accept-Ranges: bytes
Content-Type: image/jpeg
Content-Length: 2500
Content-Range: bytes 0-2499/4580
[...]
Kolejne żądanie z aplikacji klienckiej może pobrać pozostałą część zasobu.
Implementacja HATEOAS
Jedną z głównych przyczyn korzystania z architektury REST jest możliwość nawigowania po całym zestawie zasobów bez wcześniejszej wiedzy na temat schematu identyfikatora URI. Każde żądanie HTTP GET powinno zwrócić informacje niezbędne do znalezienia zasobów powiązanych bezpośrednio z żądanym obiektem za pośrednictwem hiperlinków zawartych w odpowiedzi. Żądanie powinno również zawierać informacje opisujące operacje dostępne dla każdego z tych zasobów. Ta zasada jest nazywana HATEOAS lub hipertekstem jako mechanizmem stanu aplikacji. System jest w rzeczywistości maszyną stanu skończonego, a odpowiedź na każde żądanie zawiera informacje niezbędne do przejścia z jednego stanu na inny. Żadne inne informacje nie powinny być niezbędne.
Uwaga
Nie ma żadnych standardów ogólnego przeznaczenia, które definiują sposób modelowania zasady HATEOAS. Przykłady w tej sekcji ilustrują jedno możliwe, zastrzeżone rozwiązanie.
Na przykład w celu obsługi relacji między zamówieniem a klientem reprezentacja zamówienia może zawierać linki identyfikujące dostępne operacje klienta zamówienia. Następujący blok kodu jest możliwą reprezentacją:
{
"orderID":3,
"productID":2,
"quantity":4,
"orderValue":16.60,
"links":[
{
"rel":"customer",
"href":"https://api.contoso.com/customers/3",
"action":"GET",
"types":["text/xml","application/json"]
},
{
"rel":"customer",
"href":"https://api.contoso.com/customers/3",
"action":"PUT",
"types":["application/x-www-form-urlencoded"]
},
{
"rel":"customer",
"href":"https://api.contoso.com/customers/3",
"action":"DELETE",
"types":[]
},
{
"rel":"self",
"href":"https://api.contoso.com/orders/3",
"action":"GET",
"types":["text/xml","application/json"]
},
{
"rel":"self",
"href":"https://api.contoso.com/orders/3",
"action":"PUT",
"types":["application/x-www-form-urlencoded"]
},
{
"rel":"self",
"href":"https://api.contoso.com/orders/3",
"action":"DELETE",
"types":[]
}]
}
W tym przykładzie tablica links
zawiera zestaw łączy. Każde łącze reprezentuje operację w powiązanej jednostce. Dane dla każdego linku obejmują relację ("klient"), identyfikator URI (https://api.contoso.com/customers/3
), metodę HTTP i obsługiwane typy MIME. Aplikacja kliencka potrzebuje tych informacji, aby wywołać operację.
Tablica links
zawiera również informacje odwołujące się do siebie dotyczące pobranego zasobu. Te linki mają relację self.
Zestaw zwracanych łączy może ulec zmianie w zależności od stanu zasobu. Pomysł, że hipertekst jest aparatem stanu aplikacji, opisuje ten scenariusz.
Wersjonowanie
Internetowy interfejs API nie pozostaje statyczny. W miarę zmiany wymagań biznesowych dodawane są nowe kolekcje zasobów. W miarę dodawania nowych zasobów relacje między zasobami mogą ulec zmianie, a struktura danych w zasobach może zostać zmieniona. Aktualizowanie internetowego interfejsu API w celu obsługi nowych lub różnych wymagań jest prostym procesem, ale należy wziąć pod uwagę skutki, jakie mają takie zmiany w aplikacjach klienckich korzystających z internetowego interfejsu API. Deweloper, który projektuje i implementuje internetowy interfejs API, ma pełną kontrolę nad tym interfejsem API, ale nie ma takiej samej kontroli nad aplikacjami klienckimi utworzonymi przez organizacje partnerskie. Ważne jest, aby nadal obsługiwać istniejące aplikacje klienckie, umożliwiając nowym aplikacjom klienckim korzystanie z nowych funkcji i zasobów.
Internetowy interfejs API, który implementuje przechowywanie wersji, może wskazywać funkcje i zasoby, które uwidacznia, a aplikacja kliencka może przesyłać żądania kierowane do określonej wersji funkcji lub zasobu. W poniższych sekcjach opisano kilka różnych podejść, z których każdy ma własne korzyści i kompromisy.
Brak przechowywania wersji
Takie podejście jest najprostsze i może działać w przypadku niektórych wewnętrznych interfejsów API. Istotne zmiany mogą być reprezentowane jako nowe zasoby lub nowe linki. Dodanie zawartości do istniejących zasobów może nie stanowić zmiany powodującej niezgodność, ponieważ aplikacje klienckie, nie spodziewając się tej zawartości, po prostu ją ignorują.
Na przykład żądanie do identyfikatora URI https://api.contoso.com/customers/3
powinno zwrócić szczegóły pojedynczego klienta zawierające pola id
, name
, i address
, których oczekuje aplikacja klienta.
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
{"id":3,"name":"Fabrikam, Inc.","address":"1 Microsoft Way Redmond WA 98053"}
Uwaga
Dla uproszczenia przykładowe odpowiedzi przedstawione w tej sekcji nie zawierają linków HATEOAS.
DateCreated
Jeśli pole zostanie dodane do schematu zasobu klienta, odpowiedź wygląda następująco:
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
{"id":3,"name":"Fabrikam, Inc.","dateCreated":"2025-03-22T12:11:38.0376089Z","address":"1 Microsoft Way Redmond WA 98053"}
Istniejące aplikacje klienckie mogą nadal działać poprawnie, jeśli mogą ignorować nierozpoznane pola. W międzyczasie nowe aplikacje klienckie można zaprojektować tak, aby obsługiwały to nowe pole. Jednak mogą wystąpić bardziej drastyczne modyfikacje schematu zasobów, w tym usunięcia pól lub zmiany nazwy. Albo relacje między zasobami mogą ulec zmianie. Te aktualizacje mogą stanowić znaczące zmiany, które utrudniają poprawne funkcjonowanie istniejących aplikacji klienckich. W tych scenariuszach należy wziąć pod uwagę jedną z następujących metod:
- Wersjonowanie identyfikatora URI
- Wersjonowanie ciągu zapytania
- Wersjonowanie nagłówka
- Wersjonowanie typu nośnika
Wersjonowanie identyfikatora URI
Za każdym razem, gdy modyfikujesz internetowy interfejs API lub zmieniasz schemat zasobów, należy dodać numer wersji do identyfikatora URI dla każdego zasobu. Wcześniej istniejące identyfikatory URI powinny nadal działać normalnie, zwracając zasoby zgodne z ich oryginalnym schematem.
Na przykład address
pole w poprzednim przykładzie zostało przekształcone w pola podrzędne zawierające każdą część składową adresu, na przykład streetAddress
, city
, state
i zipCode
. Tę wersję zasobu można uwidocznić za pomocą identyfikatora URI zawierającego numer wersji, na przykład https://api.contoso.com/v2/customers/3
:
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
{"id":3,"name":"Fabrikam, Inc.","dateCreated":"2025-03-22T12:11:38.0376089Z","address":{"streetAddress":"1 Microsoft Way","city":"Redmond","state":"WA","zipCode":98053}}
Ten mechanizm przechowywania wersji jest prosty, ale zależy od serwera w celu kierowania żądania do odpowiedniego punktu końcowego. Jednak może stać się skomplikowany, ponieważ web API rozwija się przez kilka iteracji, a serwer musi obsługiwać wiele różnych wersji. Z punktu widzenia purysty aplikacje klienckie pobierają te same dane (klient 3), więc identyfikator URI nie powinien różnić się w zależności od wersji. Ten schemat komplikuje również implementację funkcji HATEOAS, ponieważ wszystkie linki muszą zawierać numer wersji w swoich identyfikatorach URI.
Wersjonowanie ciągu zapytania
Zamiast dostarczać wiele identyfikatorów URI, możesz określić wersję zasobu przy użyciu parametru w ciągu zapytania dołączonego do żądania HTTP, takiego jak https://api.contoso.com/customers/3?version=2
. Parametr wersji powinien domyślnie przyjmować wartości istotne, takie jak 1, jeśli starsze aplikacje klienckie go ominą.
Takie podejście ma zaletę semantyczną, że ten sam zasób jest zawsze pobierany z tego samego identyfikatora URI. Jednak ta metoda zależy od kodu, który obsługuje żądanie, aby przeanalizować ciąg zapytania i wysłać z powrotem odpowiednią odpowiedź HTTP. Takie podejście komplikuje również implementację funkcji HATEOAS w taki sam sposób, jak mechanizm przechowywania wersji identyfikatora URI.
Uwaga
Niektóre starsze przeglądarki internetowe i internetowe serwery proxy nie buforują odpowiedzi dla żądań zawierających ciąg zapytania w identyfikatorze URI. Niebuforowane odpowiedzi mogą obniżyć wydajność aplikacji internetowych korzystających z web API i działających na starszej przeglądarce internetowej.
Wersjonowanie nagłówka
Zamiast dołączać numer wersji jako parametr ciągu zapytania, można zaimplementować niestandardowy nagłówek wskazujący wersję zasobu. Takie podejście wymaga, aby aplikacja kliencka dodaje odpowiedni nagłówek do wszystkich żądań. Jednak kod, który obsługuje żądanie klienta, może użyć wartości domyślnej, takiej jak wersja 1, jeśli nagłówek wersji zostanie pominięty.
W poniższych przykładach użyto niestandardowego nagłówka o nazwie Custom-Header. Wartość tego nagłówka wskazuje wersję internetowego interfejsu API.
Wersja 1:
GET https://api.contoso.com/customers/3
Custom-Header: api-version=1
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
{"id":3,"name":"Fabrikam, Inc.","address":"1 Microsoft Way Redmond WA 98053"}
Wersja 2:
GET https://api.contoso.com/customers/3
Custom-Header: api-version=2
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
{"id":3,"name":"Fabrikam, Inc.","dateCreated":"2025-03-22T12:11:38.0376089Z","address":{"streetAddress":"1 Microsoft Way","city":"Redmond","state":"WA","zipCode":98053}}
Podobnie jak wersjonowanie identyfikatorów URI i wersjonowanie parametrów zapytania, należy uwzględnić odpowiedni nagłówek niestandardowy we wszystkich linkach, aby zaimplementować HATEOAS.
Wersjonowanie typu mediów
Gdy aplikacja kliencka wysyła żądanie HTTP GET do serwera internetowego, powinien użyć nagłówka Accept, aby określić format zawartości, którą może obsłużyć. Zazwyczaj celem nagłówka Accept jest umożliwienie aplikacji klienckiej określenia, czy treść odpowiedzi powinna być XML, JSON, czy inny wspólny format, który klient może przeanalizować. Można jednak zdefiniować niestandardowe typy multimediów, które zawierają informacje umożliwiające aplikacji klienckiej wskazanie oczekiwanej wersji zasobu.
W poniższym przykładzie pokazano żądanie określające nagłówek Accept z wartością application/vnd.contoso.v1+json
. Element vnd.contoso.v1
wskazuje serwer internetowy, że powinien zwrócić wersję 1 zasobu. Element json
określa, że format treści odpowiedzi powinien mieć format JSON:
GET https://api.contoso.com/customers/3
Accept: application/vnd.contoso.v1+json
Kod, który obsługuje żądanie, jest odpowiedzialny za przetwarzanie nagłówka Accept i honorowanie go w maksymalnym możliwym stopniu. Aplikacja kliencka może określić wiele formatów w nagłówku Accept, co umożliwia serwerowi sieci Web wybranie najbardziej odpowiedniego formatu treści odpowiedzi. Serwer internetowy potwierdza format danych w treści odpowiedzi przy użyciu nagłówka Content-Type:
HTTP/1.1 200 OK
Content-Type: application/vnd.contoso.v1+json; charset=utf-8
{"id":3,"name":"Fabrikam, Inc.","address":"1 Microsoft Way Redmond WA 98053"}
Jeśli nagłówek Accept nie określi żadnych znanych typów multimediów, serwer internetowy może wygenerować komunikat odpowiedzi HTTP 406 (Nie do przyjęcia) lub zwrócić komunikat z domyślnym typem nośnika.
Ten mechanizm wersjonowania jest prosty i odpowiedni dla architektury HATEOAS, która może zawierać typ MIME powiązanych danych w odnośnikach zasobów.
Uwaga
Po wybraniu strategii przechowywania wersji implikacje, szczególnie w odniesieniu do buforowania serwera internetowego. Schematy przechowywania wersji identyfikatora URI i ciągu zapytania są przyjazne dla pamięci podręcznej, ponieważ ta sama kombinacja identyfikatora URI lub ciągu zapytania odwołuje się do tych samych danych za każdym razem.
Mechanizmy wersjonowania nagłówków i typów nośników zwykle wymagają więcej logiki do zbadania wartości w nagłówku niestandardowym lub nagłówku Accept. W środowisku na dużą skalę wielu klientów korzystających z różnych wersji internetowego interfejsu API może spowodować znaczną ilość zduplikowanych danych w pamięci podręcznej po stronie serwera. Ten problem może stać się ostry, jeśli aplikacja kliencka komunikuje się z serwerem internetowym za pośrednictwem serwera proxy, który implementuje buforowanie i przekazuje żądanie tylko do serwera internetowego, jeśli obecnie nie zawiera kopii żądanych danych w pamięci podręcznej.
Wielodostępne internetowe interfejsy API
Wielodostępne rozwiązanie internetowego interfejsu API jest współdzielone przez wielu najemców, takich jak odrębne organizacje posiadające swoje własne grupy użytkowników.
Model wielodostępności znacząco wpływa na projektowanie interfejsu API sieciowego, ponieważ określa sposób uzyskiwania dostępu do zasobów i wyszukiwania ich w ramach wielu dzierżaw w jednym interfejsie API sieciowym. Zaprojektuj interfejs API z myślą o wielodostępności w pamięci, aby uniknąć potrzeby przyszłej refaktoryzacji w celu zaimplementowania izolacji, skalowalności lub dostosowań specyficznych dla najemcy.
Dobrze zaprojektowany interfejs API powinien jasno definiować sposób identyfikowania klientów w żądaniach, czy to za pomocą poddomen, ścieżek, nagłówków czy tokenów. Ta struktura zapewnia spójne, ale elastyczne środowisko dla wszystkich użytkowników w systemie. Aby uzyskać więcej informacji, zobacz Mapuj żądania do dzierżawcy w rozwiązaniu multitenantowym.
Wielodzielenie ma wpływ na strukturę punktów końcowych, obsługę zapytań, uwierzytelnianie oraz autoryzację. Takie podejście wpływa również na sposób kierowania i przetwarzania żądań bram interfejsu API, modułów równoważenia obciążenia i usług zaplecza. Poniższe strategie to typowe sposoby osiągnięcia wielodostępności w internetowym interfejsie API.
Użyj izolacji poddomeny lub izolacji opartej na domenie (dzierżawa na poziomie DNS)
Takie podejście kieruje żądania przy użyciu domen specyficznych dla najemcy. Domeny wieloznaczne używają domen podrzędnych w celu zapewnienia elastyczności i prostoty. Domeny niestandardowe, które umożliwiają dzierżawcom korzystanie z własnych domen, zapewniają większą kontrolę i mogą być dostosowane do określonych potrzeb. Obie metody polegają na właściwej konfiguracji DNS, w tym rekordów A
i CNAME
, aby kierować ruch do odpowiedniej infrastruktury. Domeny wieloznaczne upraszczają konfigurację, ale domeny niestandardowe zapewniają bardziej markowe doświadczenie.
Zachowaj nazwę hosta między zwrotnym serwerem proxy a usługami zaplecza, aby uniknąć problemów, takich jak przekierowywanie adresów URL, oraz zapobiec uwidacznianiu wewnętrznych adresów URL. Ta metoda zapewnia prawidłowy routing ruchu specyficznego dla najemcy i pomaga chronić infrastrukturę wewnętrzną. Rozwiązywanie DNS ma kluczowe znaczenie dla zapewnienia lokalizacji danych i zgodności z przepisami.
GET https://adventureworks.api.contoso.com/orders/3
Wysyłanie nagłówków HTTP specyficznych dla dzierżawcy
Informacje o dzierżawcach mogą być przekazywane za pośrednictwem niestandardowych nagłówków HTTP, takich jak X-Tenant-ID
lub X-Organization-ID
, lub za pośrednictwem nagłówków opartych na hoście, takich jak Host
lub X-Forwarded-Host
, albo mogą być wyodrębnione z claimów JSON Web Token (JWT). Wybór zależy od możliwości routingu bramy interfejsu API lub zwrotnego serwera proxy, przy czym rozwiązania oparte na nagłówkach wymagają bramy warstwy 7 (L7) do inspekcji każdego żądania. To wymaganie zwiększa obciążenie związane z przetwarzaniem, co zwiększa koszty obliczeń podczas skalowania ruchu. Jednak izolacja oparta na nagłówku zapewnia kluczowe korzyści. Umożliwia scentralizowane uwierzytelnianie, co upraszcza zarządzanie zabezpieczeniami w wielodostępnych interfejsach API. Korzystając z zestawów SDK lub klientów interfejsu API, kontekst najemcy jest dynamicznie zarządzany w czasie działania, co zmniejsza złożoność konfiguracji po stronie klienta. Ponadto przechowywanie kontekstu dzierżawy w nagłówkach skutkuje bardziej czytelnym projektowaniem interfejsu API RESTful, unikając umieszczania danych specyficznych dla dzierżawy w identyfikatorze URI.
Ważną kwestią dla routingu opartego na nagłówkach jest to, że komplikuje buforowanie, szczególnie gdy warstwy pamięci podręcznej opierają się wyłącznie na kluczach opartych na identyfikatorze URI i nie uwzględniają nagłówków. Ponieważ większość mechanizmów buforowania optymalizuje wyszukiwanie identyfikatorów URI, poleganie na nagłówkach może prowadzić do fragmentowanych wpisów pamięci podręcznej. Fragmentowane wpisy zmniejszają liczbę trafień pamięci podręcznej i zwiększają obciążenie zaplecza. Co ważniejsze, jeśli warstwa buforowania nie rozróżnia odpowiedzi według nagłówków, może udostępniać buforowane dane przeznaczone dla jednego najemcy innemu, co stwarza ryzyko wycieku danych.
GET https://api.contoso.com/orders/3
X-Tenant-ID: adventureworks
lub
GET https://api.contoso.com/orders/3
Host: adventureworks
lub
GET https://api.contoso.com/orders/3
Authorization: Bearer <JWT-token including a tenant-id: adventureworks claim>
Przekazywanie informacji dotyczących najemcy za pośrednictwem ścieżki adresu URL
To podejście dodaje identyfikatory najemców w strukturze hierarchicznej zasobów i opiera się na bramie interfejsu API lub zwrotnym serwerze proxy w celu określenia odpowiedniego najemcy na podstawie segmentu ścieżki. Izolacja oparta na ścieżkach jest skuteczna, ale narusza projekt RESTful internetowego interfejsu API i wprowadza bardziej złożoną logikę routingu. Często wymaga dopasowania wzorców lub wyrażeń regularnych do analizy i normalizacji ścieżki URI.
Natomiast izolacja oparta na nagłówkach przekazuje informacje o dzierżawie za pośrednictwem nagłówków HTTP w formie par klucz-wartość. Oba podejścia umożliwiają efektywne udostępnianie infrastruktury w celu obniżenia kosztów operacyjnych i zwiększenia wydajności w dużych, wielodostępnych internetowych interfejsach API.
GET https://api.contoso.com/tenants/adventureworks/orders/3
Włącz rozproszone śledzenie i kontekst śledzenia w interfejsach API
Ponieważ systemy rozproszone i architektury mikrousług stają się standardem, złożoność nowoczesnych architektur zwiększa się. Używanie nagłówków, takich jak Correlation-ID
, X-Request-ID
lub X-Trace-ID
, do propagowania kontekstu śledzenia w żądaniach interfejsu API jest najlepszym rozwiązaniem w celu uzyskania kompleksowej widoczności. Takie podejście umożliwia bezproblemowe śledzenie żądań w miarę ich przepływu z klienta do usług zaplecza. Ułatwia szybkie identyfikowanie błędów, monitorowanie opóźnienia i mapowanie zależności interfejsu API między usługami.
Interfejsy API, które obsługują dołączanie informacji śledzenia i kontekstu, zwiększają poziom swojej obserwowalności i możliwości debugowania. Dzięki włączeniu śledzenia rozproszonego te interfejsy API umożliwiają bardziej szczegółowe zrozumienie zachowania systemu i ułatwienie śledzenia, diagnozowania i rozwiązywania problemów w złożonych środowiskach z wieloma usługami.
GET https://api.contoso.com/orders/3
Correlation-ID: 0f8fad5b-d9cb-469f-a165-70867728950e
HTTP/1.1 200 OK
...
Correlation-ID: 0f8fad5b-d9cb-469f-a165-70867728950e
{...}
Model dojrzałości internetowego interfejsu API
W 2008 roku Leonard Richardson zaproponował, co jest obecnie znane jako Richardson Maturity Model (RMM) dla internetowych interfejsów API. Program RMM definiuje cztery poziomy dojrzałości dla internetowych interfejsów API i opiera się na zasadach REST jako podejścia architektonicznego do projektowania usług internetowych. W programie RMM wraz ze wzrostem poziomu dojrzałości API staje się bardziej zgodny z REST i ściślej przestrzega zasad REST.
Te poziomy są następujące:
- Poziom 0: Zdefiniuj jeden identyfikator URI, a wszystkie operacje to żądania POST do tego identyfikatora URI. Proste usługi sieci Web protokołu dostępu do obiektów są zwykle na tym poziomie.
- Poziom 1: Utwórz oddzielne identyfikatory URI dla poszczególnych zasobów. Ten poziom nie jest jeszcze RESTful, ale zaczyna wykazywać zgodność z zasadami projektowania RESTful.
- Poziom 2: Użyj metod HTTP, aby zdefiniować operacje na zasobach. W praktyce wiele opublikowanych internetowych interfejsów API jest w przybliżeniu dopasowanych do tego poziomu.
- Poziom 3: Użyj hipermedia (HATEOAS). Ten poziom jest naprawdę interfejsem API RESTful, zgodnie z definicją Fieldinga.
Inicjatywa OpenAPI
Inicjatywa OpenAPI została utworzona przez konsorcjum branżowe w celu standaryzacji opisów interfejsów API REST u różnych dostawców. Specyfikacja standaryzacji została nazwana Swagger, zanim została przeniesiona w ramach inicjatywy OpenAPI i zmieniono nazwę na Specyfikację OpenAPI (OAS).
Rozważ wdrożenie OpenAPI dla swoich internetowych interfejsów API RESTful. Rozważ następujące kwestie:
Specyfikacja OAS zawiera zestaw opiniotwórczych wytycznych dotyczących projektowania interfejsu API REST. Wytyczne są korzystne dla współdziałania, ale wymagają upewnienia się, że projekt jest zgodny ze specyfikacjami.
Interfejs OpenAPI promuje podejście oparte na umowie zamiast podejścia opartego na implementacji. Metoda kontraktowa oznacza, że najpierw projektujesz interfejs API, a następnie piszesz kod, który implementuje ten kontrakt.
Narzędzia takie jak Swagger (OpenAPI) mogą generować biblioteki klienta lub dokumentację z kontraktów interfejsu API. Aby zapoznać się z przykładem, zobacz dokumentację internetowego interfejsu API platformy ASP.NET Core w programie Swagger/OpenAPI.
Następne kroki
- Zobacz szczegółowe zalecenia dotyczące projektowania interfejsów API REST na platformie Azure.
- Zobacz listę kontrolną elementów, które należy wziąć pod uwagę podczas projektowania i implementowania internetowego interfejsu API.
- Tworzenie architektur oprogramowania jako usługi i wielodostępnych rozwiązań na platformie Azure.