Publikujemy projekt Standardu interfejsu programistycznego aplikacji dla otwartych danych – OD.API.
To pierwszy z 4 standardów otwartości danych publicznych, jakie zostaną wypracowane w projekcie (kolejne to standardy techniczne, bezpieczeństwa i regulacji prawnych).
Standard określa minimalne rekomendowane zalecenia dotyczące interfejsu programistycznego aplikacji dostępu do baz danych, które przechowują dane publiczne. Został stworzony z myślą o administracji publicznej, aby udostępniała swoje dane przez API według jednolitego standardu.
Udostępnienie danych przez administrację publiczną zgodnie ze standardem ułatwi wykorzystanie danych publicznych i łączenie ich z różnych źródeł, a w konsekwencji tworzenie innowacyjnych dóbr, usług i produktów przez przedsiębiorców, organizacje pozarządowe, programistów.
Jeśli korzystasz lub planujesz korzystanie z API udostępniających dane publiczne, jesteś zainteresowany tematem standardów, to podziel się swoją opinią na temat projektu standardu API do 09.03.2018 r. .
KONSULTACJE ZAKOŃCZONE
OD.API
standardy interfejsu programistycznego aplikacji
Minimalne rekomendowane zalecenia dotyczące interfejsu programistycznego aplikacji dostępu do baz danych przechowujących zasoby publiczne
Słownik pojęć
API (ang. Application Program Interface) – jest przede wszystkim specyfikacją wytycznych jak powinna przebiegać interakcja miedzy komponentami programowymi. Implementacja API jest zestawem rutyn, protokołów i rozwiązań informatycznych do budowy aplikacji komputerowych. Dodatkowo API może korzystać z komponentów graficznego interfejsu użytkownika (GUI). Dobre API ułatwia budowę oprogramowania sprowadzając ją do łączenia przez programistę bloków elementów w ustalonej konwencji.
OD.API (Otwarte Dane API) – zdefiniowane niniejszym dokumentem standardy interfejsu programistycznego aplikacji (API), tj. minimalne rekomendowane zalecenia dotyczące interfejsu programistycznego aplikacji (API) dostępu do baz danych przechowujących zasoby publiczne.
program otwierania danych publicznych (PODP)[1] – program, którego celem jest poprawa jakości i zwiększenie liczby danych dostępnych na portalu danepubliczne.gov.pl
informacja sektora publicznego[2] (ang. public sector information – PSI) – przez informację sektora publicznego należy rozumieć każdą treść lub jej część, niezależnie od sposobu utrwalenia, w szczególności w postaci papierowej, elektronicznej, dźwiękowej, wizualnej lub audiowizualnej, będącą w posiadaniu podmiotów, o których mowa w art. 3 ustawy.
dane publiczne[3] (ang. public data) – liczby i pojedyncze wydarzenia lub obiekty na możliwie najniższym poziomie agregacji, które nie zostały poddane przez administrację publiczną przetworzeniu do postaci raportów, wykresów, itp. oraz nie został im nadany odpowiedni kontekst lub interpretacja. Ustrojodawca nie posługuje się terminem „danych publicznych” w ustawie o ponownym wykorzystywaniu informacji sektora publicznego.
ponowne wykorzystywanie[4] (ang. re-use) – wykorzystywanie przez osoby fizyczne, osoby prawne i jednostki organizacyjne nieposiadające osobowości prawnej, zwane dalej „użytkownikami”, informacji sektora publicznego, w celach komercyjnych lub niekomercyjnych innych niż pierwotny publiczny cel, dla którego informacja została wytworzona. Ponowne wykorzystywanie zwane jest także jako re-use (z ang. ponowne użycie).
REPSI[5] – informacja sektora publicznego, w szczególności dane publiczne, na potrzeby ponownego wykorzystywania (z ang. re-use of public sector information).
jednostka informacji publicznej[6] – najmniejszy wyodrębniony element zasobu informacyjnego spójny pod względem technicznym lub semantycznym.
zasoby informacyjne[7] – informacje publiczne o szczególnym znaczeniu dla rozwoju innowacyjności w państwie i rozwoju społeczeństwa informacyjnego, które ze względu na sposób przechowywania i udostępniania pozwalają na ich ponowne wykorzystywanie w rozumieniu przepisów ustawy w sposób użyteczny i efektywny; udostępniane w centralnym repozytorium.
jakość informacji sektora publicznego – określenie poziomu spełnienia zespołu czynników za pomocą metody Open Data Quality Model (ODQM). Ta zweryfikowana naukowo metoda dostarcza ocenę użyteczności pojedynczych informacji oraz całych zbiorów.
[1] Przyjęty uchwałą nr 107/2016 Rady Ministrów z dnia 20 września 2016 r. w sprawie ustanowienia „Programu otwierania danych publicznych”.
[2] Informacja sektora publicznej została zdefiniowana w ustawie z dnia 25 lutego 2016 r. o ponownym wykorzystywaniu informacji sektora publicznego (Dz. U. z 2016 r. poz. 352).
[3] Zdefiniowane w Programie Otwierania Danych Publicznych.
[4] Zdefiniowane w ustawie z dnia 25 lutego 2016 r. o ponownym wykorzystywaniu informacji sektora publicznego (Dz. U. z 2016 r. poz. 352).
[5] Zob. M. Możejewski „Model pomiaru jakości informacji publicznej na potrzeby ponownego użycia”, rozprawa doktorska.
[6] Zdefiniowana w rozporządzeniu Rady Ministrów z dnia 12 marca 2014 r. w sprawie Centralnego Repozytorium Informacji Publicznej (Dz. U. z 2014 r. poz. 361 z późn. zm.).
[7] Zdefiniowane w ustawie z dnia 25 lutego 2016 r. o ponownym wykorzystywaniu informacji sektora publicznego (Dz. U. z 2016 r. poz. 352),
Kontekst organizacyjny API
Głównym celem Programu Otwierania Danych Publicznych (PODP) jest poprawa jakości izwiększenie liczby danych dostępnych w portalu danepubliczne.gov.pl, a jeśli w portalu, to również za pomocą API będącym jego częścią. Samo zwiększenie liczby danych jest celem połowicznym. Pokazuje to dobitne scenariusz brytyjski. Wielka Brytania, uznawana za lidera w dziedzinie otwartości i dostępności danych publicznych, w 2017 roku zrobiła krok wstecz: wyłączyła API brytyjskiego odpowiednika danepubliczne.gov.pl. Portal data.gov.uk, należy dogrona światowych liderów pod względem liczby zasobów. Nie można zapominać, że Wielka Brytania, jako jedna z pierwszych, uruchomiła takie API w 2015 roku. Jednak jej przykład pokazuje, że o powodzeniu API nie decyduje pierwszeństwo, czy duża ilość zawartych w nim danych. Kluczową rolę kluczową odgrywa natomiast jakość. Jakość informacji sektora publicznego, na potrzeby ponownego wykorzystywania została zdefiniowana przez M. Możejewskiego, który w doktoracie z 2015 roku twierdzi, że „istotną barierą przy ponownym użyciu informacji publicznej jest również jej jakość. Problem ten może przejawiać się poprzez niską jakość lub też brak metainformacji o jakości informacji (…). Wiele opracowań podkreśla ten problem, stawiając go jednocześnie na równi z brakiem informacji. A to oznacza, że informacja o niskiej jakości lub brak informacji o jakości informacji (…) skutkuje w rezultacie ogólną nieprzydatnością zgromadzonej informacji publicznej, a cały jej potencjał jest niweczony.”[1] A potencjał ponownego wykorzystania jest ogromny[2]. Dlatego w tym kontekście brytyjski krok wydaje się odważny i uzasadniony, a można przewidywać, że podobny los może spotkać rozbudowany portal amerykański data.gov. I mimo tego, że jest to zapewne sytuacja przejściowa, to pokazuje ona, że konieczna jest zmiana podejścia w myśleniu o REPSI. Na te potrzeby odpowiada PODP formułując w celu strategicznym konieczność podnoszenia jakości zasobów REPSI.”
[1] M. Możejewski „Model pomiaru jakości informacji publicznej na potrzeby ponownego użycia”, rozprawa doktorska.
[2] M. Możejewski, „Strategia, standaryzacja i pomiar jakości informacji – determinanty efektywnego ponownego wykorzystania informacji sektora publicznego” [w:] A. Gołębiowska, P.B. Zientarski (red.), „Ponowne wykorzystanie informacji sektora publicznego w administracji”, Senat RP, Warszawa 2017, s. 65 – 90.
- , rozumianą jako konieczność posiadania przygotowania technicznego do wykonywania podstawowych interakcji z API,
- wymagać niskich nakładów czasu i pracy oraz nauki do korzystania z API,
- pozwalać na korzystanie z zasobów w sposób okazjonalny bez uwierzytelniania,
- posiadać prosty w obsłudze kreator (np. taki jak Swagger UI), który umożliwi skorzystanie z API bez konieczności wpisywania rozbudowanego kodu, lecz poprzez składanie gotowych jego elementów. Kreator może być częścią interaktywnej dokumentacji API,
- dostarczać szybko rezultatów – danych prezentowanych w przystępny dla odbiorcy sposób np. strona internetowa, z możliwością interakcji, filtrowania, sortowania i przeszukiwania oraz importu i oznaczania identyfikatorami URI reprezentacji stanów określonych zasobów,
- obsługiwać zapis/import zbudowanych przez użytkownika zapytań do API, tak aby była możliwość korzystania przez stronę z wcześniej przygotowanych zapytań (w celu umożliwienia kontynuacji pracy bez tracenia nakładu wykonanej pracy),
- użytkownicy powinni móc pozostać anonimowi, a do korzystania z kreatora nie powinna być wymagana rejestracja, zakładanie konta etc.
Grupa użytkowników zaawansowanych – to druga grupa bezpośrednich użytkowników API. W odróżnieniu od użytkowników okazjonalnych, dysponują oni wiedzą techniczną i mają już sformułowanie bezpośrednie cele i korzyści korzystania z API, gdyż podjęli już decyzję o chęci korzystania z API. To oznacza, że użytkownicy ci są zdeterminowani do integracji usług API z tworzonymi nowymi lub modyfikowanymi systemami informatycznymi. Użytkowników tych cechuje potrzeba korzystania z danych w sposób przewidywalny. Oczekują dostępności, odpowiedniej jakości danych oraz wydajności mechanizmu API, który zaspokoi każde bieżące potrzeby (których często sami nie są w stanie określić z wyprzedzeniem). Zatem w grupie użytkowników zaawansowanych znajdą się także użytkownicy okazjonalni, którzy wypróbowali już API i określili swoje oczekiwania i cele w stosunku do API. Posiadają przy tym wiedzę techniczną, zaplecze techniczne oraz zasoby, które mają być wzbogacane w oparciu o REPSI zasilane z API. W odróżnieniu od użytkowników okazjonalnych użytkownicy profesjonalni posiadają też wiedzę nt. zaawansowanych narzędzi i form komunikacji z API. Użytkownikami profesjonalnymi w głównej mierze są deweloperzy. Są oni użytkownikami, którzy mają mało czasu, podchodzą do problemów zadaniowo i chcą szybko uzyskiwać satysfakcjonujące efekty.
Ze względu na potrzeby użytkowników profesjonalnych, rekomenduje się następujące wymagania w zakresie API, które powinno:
- dostarczać interfejs z dobrze nazwanymi zasobami, który jest łatwy i intuicyjny w użyciu,
- być gotowe do natychmiastowego korzystania oraz mieć niską barierę wejścia,
- dostarczać danych o określonej jakości,
- pokazywać korzyści z używania API w kontekście konkretnych zastosowań (np. poprzez przykłady zawarte w dokumentacji),
- zaspokajać zróżnicowane potrzeby developerów,
- dostosowywać się do zmian i nowych potrzeb (zbierać propozycje od użytkowników),
- zapewniać dokumentację usług, także interaktywną,
- zapewniać obsługę wersjonowania,
- obsługiwać manipulację danych: sortowanie, filtrowanie, przeszukiwanie,
- zapewniać stabilność, wydajność oraz bezpieczeństwo (SLA),
- być traktowe jako produkt, który posiada konkurencję, a nie monopol w dostarczaniu danych. W praktyce oznaczać to będzie np. nacisk na sprawnie rozwiązywanie problemów i obsługę pytań developerów,
- zapewniać sprawnie tokeny,
- zezwalać na intensywne wykorzystanie i realizowanie gwałtownych wzrostów obciążeń,
- dostarczać usprawnienie do przesyłania (np. poprzez email) pytań, uwag, zgłoszeń błędów etc. bezpośrednio do osoby / komórki odpowiedzialnej za zasób API. Usprawnienie może być realizowane za pomocą odpowiednio spreparowanego linka „mailto” zawierającego adres email z tematem określającym identyfikator zasobu, błędu etc.,
- informować i zachęcać środowisko developerów i decydentów do korzystania.
W dalszej treści opracowania będą formułowane w ramach analizowanych aspektów API rekomendacje standaryzujące. Rekomendacje odkreślają kontekst, w którym dokonują standaryzacji elementów i cech API o zalecenia i rozwiązania techniczne.
Rekomendacja OD.API
W kontekście użytkowników API formułuje się następujące rekomendacje standaryzujące:
API powinno:
- posiadać prosty i intuicyjny interfejs,
- zapewniać dokumentację usług, także interaktywną,
- wymagać niskich nakładów czasu i pracy oraz nauki, do korzystania z API w podstawowym zakresie za pomocą prostego w obsłudze kreatora. Kreator winien umożliwiać skorzystanie z API bez konieczności wpisywania rozbudowanego kodu, lecz poprzez składanie gotowych elementów zapytań. Kreator powinien dostarczać szybko rezultatów – danych prezentowanych w przystępny dla odbiorcy sposób z możliwością interakcji: filtrowania, sortowania i przeszukiwania. Kreator może być częścią interaktywnej dokumentacji API. Kreator nie powinien wymagać zakładania konta. Powinien pozwalać na korzystanie z zasobów bez uwierzytelniania,
- zapewniać gotowość do natychmiastowego korzystania (niska bariera wejścia),
- dostarczać danych o określonej jakości,
- dostosowywać się do zmian i nowych potrzeb (zbierać propozycje od użytkowników),
- zapewniać obsługę wersjonowania,
- obsługiwać manipulację danych: sortowanie, filtrowanie, przeszukiwanie,
- zapewniać stabilność, wydajność oraz bezpieczeństwo (określone poprzez SLA),
- określać zasady intensywnego wykorzystywania i realizowanie gwałtownych wzrostów obciążeń.
Powyżej nakreślone wytyczne to tylko część wyzwań jakie stawiane są przed OD.API. Ogół wymagań ukazuje się zatem dopiero po analizie niniejszego dokumentu jako całości.
Architektura usług sieciowych REST
W założeniu OD.API oparte ma być o standard REST. Ponadto referencyjnie będzie wykorzystywało format reprezentacji danych zdefiniowany przez standard JavaScript Object Notation czyli JSON[1]. Jako standard notacji JSON przyjmuje się JSON Schema.
REST – (ang. REpresentational State Transfer) jest popularnym stylem architektonicznym stosowanym w celu budowy usług wymiany danych w sieci Internet takich jak API. API zbudowane w oparciu o zasady zdefiniowane przez REST zwane jest RESTfull API. Dzięki temu, że REST oparty jest o standardowe i powszechnie stosowane technologie, cechuje go prostota użycia (w przeciwieństwie do wsdl, soap czy uddi). REST wykorzystuje protokół HTTP[2] z uwzględnieniem jego zalet i ograniczeń. Komunikaty REST są znane z HTTP, tak jak statusy odpowiedzi, takie jak 200 (żądanie obsłużone poprawnie), 404 (nie znaleziono zasobu), 401 (brak autoryzacji), czy 500 (wewnętrzny błąd serwera).
REST jest stylem zaproponowanym w doktoracie R. Fieldinga[3] z 2000 roku i stanowi odwzorowanie idei efektywnej dystrybucji treści w rozproszonym systemie hipertekstowym. Idea ta uwzględnia jednak istotne ograniczenia, które stanowią jednocześnie kluczowe wytyczne dla REST:
- zasoby (ang. resource). W REST kluczowym elementem jest zasób. Zasób to każda porcja informacji, której postać może być określona. Przykładami zasobów są dokumenty, obrazy, informacje aktualne w określonym czasie, pogrupowane zasoby czy obiekty, pozwalające się w uproszczony sposób scharakteryzować,
- zasób jest odwzorowaniem uproszczonych cech obiektu. Cechy te muszą być spełnione (odwzorowane) zgodnie z definicją obiektu. Tylko obiekt, który odpowiada definicji odwzorowania może być zasobem. Oznacza to, że porcja informacji staje się zasobem, gdy określone są wszystkie jej cechy określone w jego definicji. Zależność tę można zdefiniować za pomocą funkcji przynależności na podstawie warunku logicznego, który przyporządkowuje zasobowi w określonym czasie unikalny identyfikator lub określone wartości. Zasób może być określony w postaci niezmiennej (gdy przyjmuje wartości statyczne), zmiennej (gdy przyjmuje wartości dynamiczne w czasie), ale może też być pusty (brak przyjętych wartości). Jedyny element, który jest wymagany i jest stały w określeniu zasobu, to semantyka mapowania tj. struktura jego elementów znaczeniowych. Nawet w przypadku zmienionych, braku lub tożsamych wartości pozwala ona na odróżnienie jednego zasobu od drugiego,
- komunikacja w modelu klient-serwer. W wymianie informacji opartej o REST istnieje wyraźna granica miedzy klientem i serwerem. Domeną klienta jest interfejs użytkownika i generowanie zapytań. Domeną serwera jest obsługa żądań klientów, w szczególności zarządzanie przechowywaniem i dostępem do danych, obciążeniem i bezpieczeństwem. Elementy te mogą być rozwijane po stronie klienta i serwera niezależnie od siebie tak długo, jak komunikacja miedzy stronami odbywa się poprzez wspólnie jednoznacznie rozumiany protokół,
- manipulacja zasobami poprzez reprezentację. Gdy klient posiada reprezentację zasobu oraz jego metadane, to posiada wszystkie informacje do tego żeby zmodyfikować lub usunąć zasób z serwera (jeśli tylko klient posiada takie uprawnienia),
- samoopisujące się komunikaty. Każdy komunikat wyposażony jest w odpowiednie informacje, które pozwalają na zarządzanie tym zasobem. Oznacza to, że komunikat oprócz treści zawiera także informacje o tym jakim paserem go odczytywać, albo czy jego zawartość może być przechowywana w pamięci cache,
- bezstanowość (ang. stateless) – oznacza rozpatrywanie zapytań niezależnie od innych (tego samego lub innego użytkownika). Cecha ta związana z wymianą informacji w modelu klient-serwer powoduje, że nie są akumulowane informacje o poprzednich transakcjach klienta, co pozwala na odciążenie serwera, jednak wymaga dodatkowych mechanizmów, jeśli podczas wymiany informacji potrzebne są dodatkowe informacje nt. użytkownika lub jego żądań[4]. Wszystkie operacje klient-serwer powinny być bezstanowe, a zarządzanie stanem powinno odbywać się po stronie klienta,
- cache’owanie zasobów – w kontekście REST odpowiedzi serwera mogą być po stronie klienta przechowywane w buforze, tak aby mogły być użyte podczas realizacji kolejnych zapytań bez konieczności pobierania ich pełnych wyników. Jednak, aby uniknąć odczytu przez klienta nieodpowiednich lub nieaktualnych danych, pobierane treści powinny być oznaczane jako możliwe do buforowanie oraz na jakich warunkach (głównie czasu ważności treści). Zaleca się, aby wszystkie zasoby mogły być buforowane, chyba, że taka możliwość zostanie wyraźnie wyłączona. Prawidłowe określenie tych parametrów pozwala eliminować kolejne interakcje klienta i serwera. Cache’owanie wpływa zatem pozytywnie na szybkość dostarczania treści do odbiorcy, pozwala korzystać z treści, nawet gdy serwer jest chwilowo niedostępny, umożliwia skalować rozwiązania oraz zmniejszać obciążenie serwera w sytuacjach gdy nie jest to niezbędne. Oznaczenie zasobów informacyjnych powinno być określane przez ich dostawców na podstawie odrębnej polityki określającej wytyczne dla warunków cache’owania,
- zastosowanie jednolitego interfejsu i unikalna identyfikacja zasobów – zasoby w systemach REST powinny być jednoznacznie oznaczane i identyfikowane za pomocą pojedynczego adresu URL. Działania wykonywane na tych zasobach (np. PUT, GET) powinny być wykonywane za pomocą poleceń protokołu HTTP,
- enkapsulacja systemów warstwami (ang. Layered System), czyli w uproszeniu przesłonienie systemów zewnętrznymi powłokami, które mają na celu wystandaryzowaną wymianę informacji. Zaletą takiego podejścia jest to, że każdy system pozostaje czarną skrzynką, a o jego przydatności decyduje tylko oddzielający go interfejs. Natomiast szczegóły wewnętrzne systemu serwera pozostają poza percepcją klientów,
- kod na żądanie (ang. Code-On-Demand), opcjonalnie – serwery są zdolne do rozszerzania lub dostosowania funkcjonalności z jakiej korzysta klient poprzez przesyłanie mu logiki, która może być wykonywana. Przykładami takiego działania może być przesyłanie klientów apletów Java lub kodu JavaScript, który wykonuje się u klienta. Jest to cecha, która w połączeniu z pozostałymi prowadzi do zwiększanie skalowalności, adaptowalności, przenośności i modyfikowalności rozwiązań budowanych w oparciu o REST.
Zatem w REST do przesłania danych potrzebny jest: zasób informacyjny, identyfikator zasobu informacyjnego, reprezentacja zasobu, reprezentacja metadanych, zasób metadanych (metadane) oraz dane kontrolne.
Rekomendacja OD.API
W kontekście stosowania standardu REST formułuje się następujące rekomendacje standaryzujące:
- Budowa API powinna być oparta o zasoby,
- Manipulacja zasobami powinna być oparta o reprezentacje zasobów,
- API powinno wspierać obsługę cache’owania,
- API powinno być wyposażone w jednolity interfejs z unikalną identyfikacją zasobów,
- Konieczne jest zapewnienie bezstanowości, wspartej obsługą tokenów w notacji JSON Web Token (JWT)[5],
- Funkcjonowanie w modelu klient-serwer, gdzie klient komunikuje się z serwerem tylko poprzez jednolity interfejs OD.API,
- Powinno być zapewnione wykorzystywanie samoopisujących się komunikatów,
- Dostarczanie zasobów powinno się odbywać w postaci niezmienionej w czasie,
- Zasoby powinny mieć znaną jakość, określaną za pomocą ODQM,
- Udostępnianie reprezentacji zasobów ma być zgodne ze strukturą określona w tabeli.
Struktura elementu danych w REST[6] |
|
resource | Byt konceptualny odwzorowany przez URI |
resource identifier | URI |
representation | dokument HTML, film MOV |
representation metadata | mediaType, expirationTime |
resource metadata | URL, alternates |
control data | cache-control |
- Jako standard notacji JSON przyjmuje się JSON Schema.
Powyższe wytyczne będą doprecyzowywane wytycznymi formułowanymi w dalszej kolejności.
Reguły nazewnictwa zasobów oraz parametry usług API
REST wykorzystuje identyfikatory zasobu do jednoznacznego określania konkretnego zasobu zaangażowanego w interakcję. Dla zachowania spójności konieczne jest stosowanie określonych reguł nazewnictwa, gdyż mają one istotny wpływ na łatwość użycia, prostotę i zrozumiałość funkcjonowania API opartego o REST. Równolegle trzeba mieć na uwadze ewoluujące w czasie reguły stosowane w poszczególnych językach lub technologiach. W przypadku REST chowane są one poza zasięgiem odbiorcy, ale nadal mogą wpływać na odwzorowanie postaci zasobów w strukturze API.
Rekomendacja OD.API
W kontekście nazewnictwa zasobów API formułuje się następujące rekomendacje standaryzujące:
- Stosowanie prostego i objaśniającego nazewnictwa,
- Oznaczanie zasobów rzeczownikami (np. czujniki, samochody),
- Stosowanie rzeczowników w liczbie mnogiej (np. formularze zamiast formularz, czujniki zamiast czujnik),
- Niestosowanie czasowników lub sformułowań opisujących czynności (np. „pobierz-formularze” lub „wyswietla-listę czujników”),
- Stosowanie nazewnictwa konkretnie wskazujące na zasób zamiast nazewnictwa gdzie znaczenie wymaga znajomości kontekstu do jego zrozumienia (np. „przeglady” zamiast „przeglady-rejestracyjne”),
- Niestosowanie polskich znaków w polach będących identyfikatorem zasobów (np.: usługi), zwłaszcza, jeżeli są one wykorzystywane w URI zasobu,
- Oznaczanie zasobów za pomocą małych liter[7] (np. pojazdy-zarejestrowane zamiast Pojazdy-Zarejestrowane),
- Używanie „-” (myślników) do łącznia fraz złożonych (np. pojazdy-zarejestrowane zamiast pojazdyzarejestrowane),
- Nieużywanie „_” (znaków podkreślenia) do łącznia fraz złożonych (np. pojazdy-zarejestrowane zamiast pojazdy_zarejestrowane),
Opis składni oraz elementów URI
Definicje związane z oznaczeniem zasobów:
Schemat (ang. authority) – komponent URI, który definiuje protokół wymiany informacji (np. HTTP) oraz przestrzeń,
Zasób główny (ang. docroot) – zasób, który jest nadrzędny wobec pozostałych w API w modelu REST,
Artefakty zasobów – zbiór czterech wewnętrznych pojęć: dokument (ang. document), kolekcja (ang. collection), sklep (ang. store) i kontroler (ang. controller), które mogą być używane do opisu interfejsu API REST,
Dokument (ang. document) – reprezentacja pojedynczego wystąpienia zasobu,
Kolekcja (ang. collection) – artefakt zasobu używanego do modelowania grupy zasobów po stronie serwera,
Sklep (ang. store) – artefakt zasobu wykorzystywany do modelowania repozytorium zarządzanego przez klienta,
Kontroler (ang. controller) – artefakt zasobu, który jest używany do modelowania koncepcji proceduralnej,
CRUD – akronim od nazw czterech podstawowych funkcji operowania na danych w bazach danych: create (pol. utwórz), retrieve (pol. odczytaj), update (pol. aktualizuj) and delete (pol. usuń),
„Bezpieczne metody” HTTP – metody GET i HEAD, które umożliwiają uzyskiwanie reprezentacji zasobów, ale nie pozwalają na modyfikację i usuwanie zasobów na serwerze,
Zasób nadrzędny (ang. parent resource) – dokument, kolekcja lub sklep, który dostarcza odpowiedniego stanu zasobu poprzez odwołanie za pomocą URI,
Pytanie lub zapytanie lub kwerenda (ang. query) – fragment URI występujący za ścieżką, ale przed opcjonalnym fragmentem,
URI (z ang. Uniform Resource Identyficator) jest unikalnym identyfikatorem zasobów. Stosowanie URI powinno być zgodne z funkcjonalnymi rekomendacjami dla URI określonymi w RFC 1736 oraz RFC 1737. Składania URI powinna być unikalna i zgodna na poziomie ogólnym z wytycznymi określonymi przez standard RFC 3986[8], zgodnie z którym podstawowe oznaczenie URI przyjmuje następująca postać:
URI = <schemat> „:” <część hierarchiczna> [ „?” <pytanie> ] [ „#” <fragment> ] |
Ogólna postać URI zakłada występowanie schematu (np. protokołu), określonej hierarchii (np. domeny i/lub odwołania lokalnego), zapytań oraz wskazania wybranych fragmentów. Część hierarchiczna może zawierać odwołanie do domeny podmiotu i/lub ścieżki lokalnej. Elementy <pytanie> oraz <fragment> są składowymi, które nie muszą być podane. Element <pytanie> zwany jest też kwerendą.
URI często jest utożsamiany z URL, a same nazwy stosowane są wymiennie. Jest to jednak błąd, gdyż URI jest pojęciem różnym w stosunku do URL. W skrócie różnica polega na tym, że URI identyfikuje zasób, natomiast URL zawiera przede wszystkim referencję w zakresie lokalizacji zasobu. Dokumentacja RFC wskazuje, że powinno się dążyć do używania pojęcia URI jako generalnego w tym kontekście, jednak rozróżnienie między URI i URL jest bardzo istotne w technologii RDF, stanowiącej krok w stronę Semantic Web – sieci trzeciej generacji.
- Domena w URI powinna wskazywać jednoznacznie na właściciela API. Domena ta powinna udostępniać funkcjonalność API poprzez subdomenę „api”.
Przykład:
http://api.danepubliczne.gov.pl |
Powyższe zalecenie wynika z zastosowania tzw. dobrej praktyki przy udostępnianiu REPSI poprzez API. Mimo, że popularne są także odmienne podejścia (np. udostępnianie zasobów API w ścieżce) to wydzielenie zasobów w zaproponowany sposób jest szczególnie stosowane przez liczne światowe API udostępniające informacje sektora publicznego[9]. Takie rozwiązanie poprawia również czytelność i rozpoznawalność zasobów API. Dlatego warto tę konwencję utrzymać. Z drugiej strony API dostępne w wydzielonej subdomenie pozwala na zwiększenie bezpieczeństwa poprzez możliwość izolacji ustawień (per-domena) oraz ułatwia zarządzanie przyszłą migracją. Zalecenie takie wynika również z literatury przedmiotu, która określa prezencyjnie, że stosując wytyczne REST dla API powinno udostępniać się API w subdomenie[10].
- API powinno być wyposażone w portal dla developerów, który zawiera dokumentację API, instrumenty wsparcia takie jak forum, generator tokenów etc. Portal powinien być integralna częścią API i być dostępny poprzez subdomenę „dev”. Portal powinien być wyposażony w GUI. Jego celem jest wsparcie obecnych oraz pozyskanie nowych korzystających w API.
Przykład:
http://dev.danepubliczne.gov.pl |
Wytyczne, podobnie jak w przypadku punktu pierwszego, wynikają z zastosowania przyjętej dobrej praktyki do zapewniania wsparcia dla deweloperów w jednym wydzielonym miejscu. Literatura przedmiotu także w tym wypadku określa, że miejsce to powinno być oznaczone wydzieloną subdomeną „developer”[11]. Z uwagi na fakt, ze adres portalu danepubliczne.gov.pl jest już znacznej długości zaleca się stosowanie oznaczenia alternatywnego „dev”.
- Znak „/” (ukośnik, ang. forward slash) służy oznaczeniu zależności hierarchicznej miedzy zasobami.
Przykład:
http://api.danepubliczne.gov.pl/cepik/pojazdy-zarejestrowane/zachodniopomorskie/szczecin |
- Stosowanie znaku „/” (ukośnik, ang. forward slash) na końcu URI nie jest dopuszczone.
Przykład:
http://api.data.gov.pl/cepik/poajzdy-zarejestrowane/zachodniopomorskie/szczecin/ |
Ponieważ adresy zawierające znak „/” na końcu URI, jak i bez tego znaku, będą traktowane przez różne interfejsy jako tożsame, zatem nie będzie spełniona podstawowa cecha URI – unikalnego identyfikowania zasobu, co jest również podstawową cechą architektury REST.
- Oznaczanie ścieżki URI z użyciem małych liter.
Przykład:
http://API.danepubliczne.gov.pl/lista-zasobow
oraz http://api.danepubliczne.gov.pl/lista-zasobow |
URI zapisane wielkimi i małymi literami w powyższym przykładzie w praktyce są tożsame, gdyż zgodnie z RFC 3986 nie jest rozróżniana wielkość liter w elemencie reprezentowanym przez domenę i subdomenę. Ponieważ wytyczne w stosunku do nazewnictwa zasobów wskazują konieczność używania małych liter to dla zachowania jednoznaczności także dla URI formułuje się taką zasadę.
- W URI NIE stosuje się rozszerzeń plików oraz nazw formatów danych. Informacje te są przekazywane przez nagłówki (ang. headers).
Przykład:
http://api.danepubliczne.gov.pl/cepik/pojazdy-zarejestrowane/zachodniopomorskie/szczecin.json |
Używanie w URI nazwy użytkownika z hasłem, najczęściej stanowi poważną lukę w bezpieczeństwie i z tego powodu nie jest zalecane.
Rekomendacja OD.API
W kontekście składni URI formułuje się następujące rekomendacje standaryzujące:
- Domena w URI powinna wskazywać jednoznacznie na właściciela API. Domena ta powinna udostępniać funkcjonalność API poprzez subdomenę „api”,
- API powinno być wyposażone w portal dla developerów, który zawiera dokumentację API, instrumenty wsparcia takie jak forum, generator tokenów etc. Portal powinien być integralna częścią API i być dostępny poprzez subdomenę „dev”. Portal powinien być wyposażony w GUI. Jego celem jest wsparcie obecnych oraz pozyskanie nowych korzystających z API,
- Znak „/” (ukośnik, ang. forward slash) służy oznaczeniu zależności hierarchicznej miedzy zasobami,
- Stosowanie znaku „/” (ukośnik, ang. forward slash) na końcu URI nie jest wskazane,
- Ścieżki URI powinny być oznaczane z użyciem małych liter,
- W URI NIE stosuje się rozszerzeń plików oraz nazw formatów danych. Informacje te przekazywane są przez nagłówki (ang. headers).
Opis dostępu do zasobów powiązanych za pomocą URI
W REST klient dostarcza stan poprzez ciało zapytania, parametry zawarte w kwerendzie, nagłówki. Usługa API dostarcza klientowi stan poprzez ciało komunikatu, kody i nagłówki odpowiedzi. Technicznie oznacza to komunikację za pomocą hiperlinków i hipertekstu. REST może używać techniki HATEOS czyli linków zawartych w ciele lub nagłówkach odpowiedzi, które zawierają identyfikatory URI do zasobów powiązanych. Mechanizm udostępniania linków zostanie omówiony w dalszej części.
Manipulowanie zasobami (filtrowanie, sortowanie, stronicowanie)
W założeniu szereg klienckich aplikacji będzie korzystać z zasobów API automatycznie. Aplikacje takie rzadko realizują zadania wymagające pobrania z API zbioru danych w pełnym przekroju informacyjnym oraz pełnej zawartości rekordów. Znacznie częściej potrzebują odpowiednio spreparowanego, niewielkiego wycinka zamiast pełnego zakresu dostępnych danych. Wycinek ten w stosunku do oryginalnego zbioru może być filtrowany względem zakresu pobieranych danych, w kontekście określonych kryteriów, porcji danych pobieranej za jednym razem oraz w odpowiednim uprządkowaniu. Dlatego założono, że API udostępniać będzie funkcjonalność filtrowania, sortowania i stronicowania wybranych zasobów, które określane będzie mianem manipulacji danymi.
Interakcja z API w zakresie filtrowania, sortowania, stronicowania wybranych zasobów oparta jest o mechanizm URI, który zawiera sekcję <pytanie>. Jest to element nieobowiązkowy w URI, lecz niezbędny w przypadku potrzeby manipulacji zakresem lub strukturą danych przed pobraniem.
URI = <schemat> „:” <część hierarchiczna> [ „?” <pytanie> ] [ „#” <fragment> ]
Zasady manipulacji danymi zostaną przedstawione za pomocą kolejnych przykładów. Punktem odniesienia do wykonywania operacji manipulowania danymi jest pełna lista zasobów, czyli tzw. kolekcja uzyskiwana za pomocą następującego odwołania do zasobu głównego.
GET /
W wyniku uzyskiwana jest odpowiedź, która jest reprezentacją stanu zawierającą listę wszystkich zasobów.
Natomiast po wykonaniu kodu z przykładu:
GET /cepik/pojazdy
uzyskiwana jest reprezentacja stanu zawierająca listę elementów zasobu „pojazdy”.
Filtrowanie zasobów – służy do ograniczania wyników jedynie do tych, które spełniają zadane warunki. W rezultacie kolekcję ogranicza się jedynie do listy zawierającej zasoby odpowiadające kryteriom przekazanym w URI w części <zapytanie>.
GET /?filter=zasoby-danych:cepik
W wyniku wykonania powyższego zapytania uzyskiwana jest reprezentacja stanu zawierająca zasób danych o nazwie „cepik”.
GET /cepik/pojazdy?filter=rodzaj:osobowe
W wyniku uzyskiwana jest reprezentacja stanu zawierająca listę pojazdów, które dla wymiaru „rodzaj” spełniają warunek „osobowe”. Idąc dalej, a korzystając z tej funkcjonalności, w wyniku ogranicza się liczbę zwracanych pól jedynie do wybranych: przebiegu, roku i rodzaju oraz przy zawężeniu wyników tylko do pojazdów osobowych:
GET /cepik/pojazdy?filter=rodzaj:osobowe,przebieg,rok-produkcji
Taka funkcjonalność ma bardzo duże znaczenie dla wygody korzystania z API i jest czytelna i intuicyjna. W rezultacie uzyskuje się tylko te informacje, które akurat są w danym momencie potrzebne w aplikacji. Dzięki temu nie trzeba przesyłać zbędnych danych, co wpływa znacznie na ograniczenie transferu.
Sortowanie zasobów – służy do szeregowania elementów rosnąco lub malejąco według określonego kryterium lub kryteriów. Domyślnie zasoby powinny być sortowane rosnąco według zadanego kryterium.
GET /cepik/pojazdy?sort=rok-produkcji
Wynik: sortowanie wyników za pomocą jednego kryterium, w porządku domyślnym (rosnąco) w kolekcji „pojazdy”.
GET /cepik/pojazdy?sort=rok-produkcji,przebieg
Wynik: sortowanie wyników za pomocą więcej niż jednego kryterium, w porządku domyślnym (rosnąco).
GET /cepik/pojazdy?sort=rok-produkcji:desc,przebieg
Wynik: sortowanie za pomocą więcej niż jednego kryterium, w porządku malejącym.
Uwaga: aby wyznaczyć porządek malejący należy wybrane kryterium oznaczyć poprzez „:desc”. W odpowiedzi zostanie zwrócona lista zawierająca pojazdy uszeregowane od najmłodszego do najstarszego, przy czym pojazdy z tego samego roku zostaną posortowane rosnąco według przebiegu.
Jeśli serwer nie obsługuje danego rodzaju sortowania dla zadanego parametru serwer powinien zwracać błąd. Jeśli parametr „sort” nie został wskazany serwer używa domyślnego sortowania dla zwracanych elementów.
Stronicowanie zasobów – służy do ograniczania wyników zapytania do określonej liczby elementów zwanych stroną. Stronicowanie oparte jest o dwa parametry:
page – oznacza numer strony,
per_page – oznacza liczbę elementów wyświetlanych na jednej stronie.
GET /cepik/pojazdy?page=5&per_page=48
Oznacza wyświetlenie 48 elementów na piątej stronie.
Podsumowując powyższe kod obrazujący przykład najbardziej złożonego ze wszystkich powyższych warunków będzie miał postać następującą:
GET /cepik/pojazdy?filter=rodzaj:osobowe&sort=rok:desc,przebieg&page=5&per_page=48
Realizowanie kwerend – służy do ograniczania wyników do elementów spełniających określone kryteria zawarte w parametrycznych kwerendach.
Przykład:
GET /cepik/pojazdy/?q=rodzaj:osobowe
W wyniku wykonania powyższego zapytania zostanie uzyskana reprezentacja stanu zawierająca pojazdy, w których parametr rodzaj ma wartość „osobowe”.
Przykład:
GET /?q=rodzaj:osobowe
Wyniku wykonania powyższego zapytania zostanie uzyskana reprezentacja stanu zawierająca wszystkie elementy (nie tylko dla zasobu pojazdy), w których parametr rodzaj ma wartość „osobowe”.
Zapytania realizowane w URI mają ograniczoną funkcjonalność, która realizowana jest w szerszym zakresie w oparciu o kwerendy Query DSL zawarte w ciele żądania.
[1] Schema JSON http://www.yaml.org/spec/1.2/spec.html#id2803231 [Dostęp 12.02.2018]
[2] Hypertext Transfer Protocol (HTTP).
[3] Rozprawa doktorska R. Fieldinga „Architectural Styles and the Design of Network-based Software Architectures”, University of California 2010.
[4] Takie informacje mogą być dostarczane poprzez mechanizm ciasteczek, sesji lub ukrytych parametrów.
[5] Zob. Standard JWT dostarczany przez IETF https://tools.ietf.org/html/draft-ietf-oauth-json-web-token-32 [Dostęp 12.02.2018]
[6] Rozprawa doktorska R. Fieldinga „Architectural Styles and the Design of Network-based Software Architectures”, University of California 2010.
[7] Zgodnie z RFC 2616 ścieżka i zapytanie w URL mają rozróżnianą wielkość liter http://w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.2.3 [Dostęp 12.02.2018]
[8] Źródło: RFC 3986 dostępny jest pod adresem: https://www.ietf.org/rfc/rfc3986.txt [Dostęp 12.02.2018]
[9] Światowe zasoby REPSI dostępne poprzez API w subdomenie: api.data.gov, api.nasa.gov, data.norge.no, api.trafikinfo.trafikverket.se [Dostęp 12.02.2018]
[10] Zob. s. 14, M. Masse, REST API Design Rulebook: Designing Consistent RESTful Web Service Interfaces, O’Reilly 2012.
[11] Tamże s. 14.
Rekomendacja OD.API
W kontekście manipulowania reprezentacjami zasobów (filtrowanie, sortowanie, stronicowanie) formułuje się następujące rekomendacje standaryzujące:
- Proste stronicowanie, filtrowanie i sortowania reprezentacji zasobów powinno się odbywać poprzez URI,
- Równolegle API powinno obsługiwać zapytania przesyłane w ciele wiadomości w zakresie szerszym niż przez URI,
- Obsługa funkcjonalności stronicowania, filtrowania i sortowania API powinna być zapewniania przez warstwę pośrednią API. Rekomendowanym rozwiązaniem realizującym funkcję warstwy pośredniej jest Elasticsearch,
- Stosowanie Elasticsearch powinno uwzględniać potencjalne zagrożenia w szczególności związane z obsługa wyrażeń regularnych, opisane w szczególności w dokumentacji tego rozwiązania,
- Obsługa kwerend SQL jest niezalecana.
Przykładowy kod klienta
Zgodnie z zasadami REST, OD.API działa niezależnie od środowiska technologicznego klienta. Najpopularniejszymi z nich są JAVA, PHP, Javascript oraz Perl. Mimo, że część z nich znana jest z funkcjonowania w modelu klient-serwer typowo po stronie serwera, to w przypadku komunikacji z API mogą one obsługiwać zapytania po stronie klienta.
Poniżej zaprezentowano przykładowe fragmenty kodów aplikacji klienckich łączących się z OD.API. Kod podzielono na prosty i bardziej skomplikowany. Kod prosty będzie umożliwiał uzyskanie danych, natomiast kod złożony będzie wykonywał manipulację na danych przed pobraniem. Dla przejrzystości przykładów znaki w URI nie zostały zakodowane, a komunikacja odbywa się bez SSL.
Kod Java – wariant #1
import java.io.BufferedReader;import java.io.IOException;import java.io.InputStreamReader; import org.apache.http.HttpResponse;import org.apache.http.client.ClientProtocolException;import org.apache.http.client.HttpClient;import org.apache.http.client.methods.HttpGet;import org.apache.http.impl.client.DefaultHttpClient; public class getApiData { public static void main(String[] args) throws ClientProtocolException, IOException { HttpClient client = new DefaultHttpClient(); HttpGet getRequest = new HttpGet(‚http://api.danepubliczne.gov.pl/cepik/pojazdy’); HttpResponse httpResponse = client.execute(getRequest); BufferedReader br = new BufferedReader (new InputStreamReader(httpResponse.getEntity().getContent())); String line = ”; while ((line = br.readLine()) != null) { System.out.println(line); } }} |
Kod Java – wariant #2
import java.io.BufferedReader;import java.io.IOException;import java.io.InputStreamReader; import org.apache.http.HttpResponse;import org.apache.http.client.ClientProtocolException;import org.apache.http.client.HttpClient;import org.apache.http.client.methods.HttpGet;import org.apache.http.impl.client.DefaultHttpClient; public class getApiData { public static void main(String[] args) throws ClientProtocolException, IOException { HttpClient client = new DefaultHttpClient(); HttpHost target = new HttpHost(‚api.danepubliczne.gov.pl/cepik/pojazdy’, 80, „http”); HttpGet getRequest = new HttpGet(‚?filter=rodzaj:osobowe&sort=rok:desc,przebieg&page=5&per_page=48’) System.out.println(„Wykonywanie zapytania ” + target); HttpResponse HttpResponse = client.execute(target, getRequest); HttpEntity entity = httpResponse.getEntity(); BufferedReader br = new BufferedReader (new InputStreamReader(entity.getContent())); String line = ”; while ((line = br.readLine()) != null) { System.out.println(line); } }} |
Kod JavaScript – wariant #1
$.ajax({
url : ‚http://api.danepubliczne.gov.pl/cepik/pojazdy’, type : ‚GET’, dataType : ‚json’, success : function(json) { alert(‘Zrealizowano’); }, }); |
Kod JavaScript – wariant #2
$.ajax({
url : ‚http://api.danepubliczne.gov.pl/cepik/pojazdy’, data : { filter : ‚rodzaj:osobowe’, sort : ‚rok-produkcji,przebieg:desc’, page : 5, per_page:48, q : ”},
type : ‚GET’, dataType : ‚json’, success : function(json) { alert(‚Zrealizowano’); }, error : function(xhr, status) { alert(‚Wystąpił problem!’); }, complete : function(xhr, status) { alert(Zakończono!’); } });
|
Kod Python – wariant #1
#!/usr/bin/env pythonimport urllib2import urllibimport jsonimport pprint zapytanie = urllib2.urlopen(‚http://api.danepubliczne.gov.pl/cepik/pojazdy’)assert zapytanie.code == 200 pobrane = json.loads(response.read()) assert pobrane[‚success’] is Trueresult = pobrane[‚result’]pprint.pprint(result) |
Kod Python – wariant #2
#!/usr/bin/env pythonimport urllib2import urllibimport jsonimport pprint url = ‚http://api.danepubliczne.gov.pl/cepik/pojazdy’ parametry = ‚?filter=rodzaj:osobowe&sort=rok:desc,przebieg&page=5&per_page=48’kwerenda =”join_url = url.parametry.kwerenda rezultat = urllib2.urlopen(join_url)assert rezultat.code == 200print „Nagłówki: „, rezultat.info()print „Data: „, rezultat.info()[‚date’]print „Nagłówek serwera: „, rezultat.info()[‚server’]print „Długość odpowiedzi:”, len(rezultat.read())pobrane = json.loads(rezultat.read())assert pobrane[‚success’] is Truepprint.pprint(pobrane[‚result’]) |
Kod PHP – wariant #1
header(‚Content-type: application/json’); $url=’http://api.danepubliczne.gov.pl/cepik/pojazdy’;$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url); $data = curl_exec($ch); $data = json_decode($data); print_r(json_decode($data)); curl_close($ch);
|
Kod PHP – wariant #2
header(‚Content-type: application/json’); $uri=’http://api.danepubliczne.gov.pl/cepik/pojazdy’;$parametry = ‚?filter=rodzaj:osobowe&sort=rok:desc,przebieg&page=5&per_page=48’;$kwerenda =”;$url = $uri . $parametry . $kwerenda;$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url); curl_setopt($ch, CURLOPT_HTTPHEADER, [‚Accept:application/json, Content-Type:application/json’]); curl_setopt($ch, CURLOPT_CUSTOMREQUEST, ‚GET’);
$data = curl_exec($ch); if ($data === false) { $info = curl_getinfo($curl); curl_close($curl); die(‚Podczas przetwarzania cURL wystąpił błąd. Dodatkowe informacje: ‚ . var_export($info)); } else{ $data = json_decode($data); echo „Wierszy w zasobie”.count($data->rows); print_r(json_decode($data)); } curl_close($ch);
|
Metadane
Zasoby udostępniane przez API wyposażane są w metadane. Metadane to inaczej dane o danych, które opisując zasoby ułatwiają ich zrozumienie oraz zarządzanie nimi. Są szczególnie istotne w procesie maszynowego przetwarzania informacji, dlatego istotna jest również łatwość zrozumienia metadanych. Dlatego stosowane do określania metadanych nazwy powinny być samoopisujące. W celu określenia minimalnego zestawu metadanych w OD.API poddano analizie istniejące już rozwiązania w zakresie semantyki odwzorowania obiektów, takie jak schema.org, DCAT, CKAN API, POD. Jednak żaden z zaproponowanych standardów nie był odpowiedni do zastosowania wprost. Dodatkowo metadane muszą uwzględniać lokalne wytyczne określone przez PODP oraz rozporządzenie Rady Ministrów z dnia 12 marca 2014 r. w sprawie Centralnego Repozytorium Informacji Publicznej (Dz. U. poz. 361). Dlatego w poniższej tabeli przedstawiono minimalny zestaw metadanych dla zasobu z założeniem, że będzie on poddany standaryzacji w ramach odrębnego opracowania. OD.API definiuje minimalny zestaw metadanych dla zasobu następująco:
Nazwa | Oznaczenie | Znaczenie |
Identyfikator | resourceId | Identyfikator zasobu informacyjnego. |
Nazwa zasobu | resourceName | Nazwa zasobu informacyjnego, która umożliwia jego identyfikację (ew. nazwa zasobu z elementami charakterystycznymi). |
URL zasobu | resourceUrl | Identyfikator lokalizacji do pobrania zasobu informacyjnego (URL). |
URI zasobu | resourceUri | Identyfikator oznaczenia zasobu (URI). |
Identyfikator dostawcy zasobu | vendorId | Unikalny identyfikator dostawcy zasobu informacyjnego. |
Nazwa dostawcy | vendorName | Nazwa dostawcy zasobu informacyjnego. |
Adres dostawcy | vendorAddres | Adres pocztowy siedziby dostawcy (lub oddziału, jeśli jest to istotne dla zrozumienia zakresu lub przeznaczenia danych) wraz z adresem email. |
Osoba kontaktowa dla zasobu | resourceContactName | Imię i nazwisko osoby odpowiedzialnej za utrzymanie zasobu w API. Managera zasobu hosta API, a nie dostawcy. |
Dane kontaktowe do osoby kontaktowej | resourceContactData | Link do adresu email do managera API z automatycznie proponowanym tematem zawierającym reference_id na który można przesyłać feedback, potrzeby w zakresie zasobu lub słowa kluczowe do dodania w zasobie oraz telefon bezpośredni. |
Data publikacji zasobu | dateStart | Data od której zasób jest publikowany, z dokładnością do jednej sekundy. |
Data modyfikacji zasobu | dateLastMod | Data modyfikacji zasobu z dokładnością do jednej sekundy. |
Data zakończenia publikacji zasobu | dateStop | Data określająca do kiedy zasób jest dostępny w API. Wprowadzana wartość nie powinna być krótsza niż 12 miesięcy. Domyślnie wartość wypełniona jako pusta lub zerowa. |
Opis zasobu | description | Opis zasobu informacyjnego ma odpowiedzieć na pytania:
1. co zawiera zasób? 2. dlaczego ma go użyć naukowiec? 3. dlaczego ma go użyć przedsiębiorca?
Co najmniej w języku polskim i angielskim. |
Słowa kluczowe | keywords | Słowa kluczowe, czyli zestaw słów lub wyrażeń zwięźle opisujących zasób informacyjny.
Co najmniej w języku polskim i angielskim. |
Zawiera dane za okres od | dataPeriodStart | Informuje, że zbiór zawiera dane za okres od. Konieczne uwzględnienie okresów przerywanych. |
Zawiera dane za okres do | dataPeriodEnd | Informuje, że zbiór zawiera dane za okres do. Konieczne uwzględnienie okresów przerywanych. |
Granulacja danych | dataGranulation | Informacja nt. porcji danych opcjonalnie rozdrobnienie danych, tzn. czy są publikowane w określonych i jakich porcjach kwantowych. |
Wersja zasobu w API | version | Oznaczenie wersji zasobu w unikalny sposób w ramach API,
np. wg schematu resource-id-NR, gdzie NR oznacza kolejny numer wersji. |
Wersja zasobu u dostawcy | versionVendor | Oznaczenie wersji zasobu przez dostawcę, może zawierać numer wewnętrzny dostawcy. |
Jakość danych w zasobie | dataQuality | Określa jakość zasobu danych w pięciu klasach za pomocą modelu ODQM. |
Język zasobu | language | Określa język zasobu. |
Bieżąca Aktualizacja | dataLive | Informuje czy zasób jest aktualizowany maszynowo „na żywo”, np. pomiary temperatur dostarczane przyrostowo przez dostawcę. |
Częstotliwość aktualizacji | updateFrequency | Informuje o tym jaki jest interwał aktualizacji zasobu
(np. w formie daty, która pozwala określić aktualizacyjny period z dokładnością do jednej sekundy w czytelnej formie np. w formacie: yyyy-mm-dd hh:mm:ss dla wartości 0000-00-00 00:10:00 oznacza co 10 minut) |
Zasób o szczególnym znaczeniu | nationalInformationResource | Informacja czy zasób jest zasobem informacyjnym o szczególnym znaczeniu dla rozwoju innowacyjności w państwie i rozwoju społeczeństwa informacyjnego w myśl. art. 9a. ustawy o dostępie do informacji publicznej[1]. |
Kodowanie | dataFormat | Określenie kodowania zasobu. |
Standard zapisu | dataStandard | Określenie referencji standardu zasobu. |
Dane przestrzenne | dataSpatial | Określenie czy zasób zawiera dane przestrzenne. |
Słownik danych | dataDictionary | Słownik, którego używa zasób, określający np. znaczenie kolumn i określeń, które nie są powszechne. |
Referencja słownika danych | dataDictionaryType | Rodzaj używanego słownika. |
Dane heterogeniczne | dataMixed | Określenie czy zasób zawiera dane mieszanych rodzajów (heterogeniczne). Np. czy zasób zawiera reprezentację lub referencję złożoną z więcej niż jednego formatu danych np. tekst i obraz. |
Rodzaj mediów | mediaType | Wartość „Mimetype” dla zasobu. |
Licencja ponownego wykorzystywnia | reUseLicence | Określenie identyfikatora licencji lub warunków ograniczających wykorzystywanie. |
Ograniczenia ponownego wykorzystywania | reUseLicenceLimitations | Określa warunki ponownego wykorzystywania jednostki informacji publicznej – tekstowy opis warunków ponownego wykorzystywania, o których mowa w art. 23b ust. 2 ustawy[2], jeżeli zostały określone przez dostawcę. Warunki ponownego wykorzystywania, jeżeli są inne niż: bez ograniczeń i bezpłatnie lub informacja, że warunków nie ma. |
Link do dokumentacji API | apiDocs | Link do dokumentacji API. |
Licznik pozycji w zasobie | resourceCount | Licznik pozycji w zasobie, np. wierszy. |
Rozmiar zasobu | resourceSize | Rozmiar zasobu (bez zależnych i powiązanych) w jednostkach przyjętych dla danego formatu np. kB. |
Katalog | catalog | Określenie przynależności do grupy np. zasobów. |
Powyższa tabela zawiera minimalny zestaw metadanych, który może być rozszerzany. Ponadto szczególną rolę odgrywa właściwie dobrany i bezbłędny zestaw metadanych określany przez dostawcę, gdyż są to informacje najczęściej wykorzystywane do precyzyjnego manipulowania danymi w ramach zasobów. W oddzielnym opracowaniu, metadane będą przedmiotem analizy mającej na celu ich standaryzację.
Rekomendacja OD.API
W kontekście określania minimalnego zestawu metadanych formułuje się następujące rekomendacje standaryzujące:
- Zasoby są opisywane za pomocą minimalnego zestawu metadanych określonego w niniejszym dokumencie,
- Gdy metadane nie występują dla określonego rodzaju zasobów przyjmują wartość notApplicable,
- Metadane określane przez dostawcę zasobu określane są zgodnie ze zdefiniowanymi zasadami nazewnictwa,
W odpowiedzi na przesyłane przez użytkowników zapytania API udostępnia stany zawierające odpowiednie zasoby informacyjne. Jednak nie wszyscy użytkownicy potrzebują w odpowiedzi otrzymywać całe zasoby. Większość aplikacji użytkowników, korzystających z API potrzebuje w danym momencie często jedynie niewielkiej porcji informacji wyfiltrowanej z zasobu. Takie informacje są filtrowane za pomocą dodatkowych warunków zapytania zawartych w URI. Jednak przesłanie samego stanu zawierającego wyfiltrowany zasób użytkownikowi to za mało. Dlatego standard OD.API zapewnia funkcjonalność linków do nawigacji. Polega ona na dołączaniu w ciele zasobu poniższych linków (oznaczanych jako „links”).
Nazwa linku | Objaśnienie |
prev | Link do poprzedniego powiązanego zasobu. |
self | Link do bieżącego zasobu. |
next | Link do następnego powiązanego zasobu. |
last | Link do ostatniego powiązanego zasobu. |
Przykład:
{
„links”: { „prev”: „http://api.danepubliczne.gov.pl/cepik/pojazdy?start=15&limit=5”, „self”: „http://api.danepubliczne.gov.pl/cepik/pojazdy”, „next”: „http://api.danepubliczne.gov.pl/cepik/pojazdy?start=25&limit=5”, „last”: „http://api.danepubliczne.gov.pl/cepik/pojazdy?start=50&limit=5”, }, } |
API powinno również aktywnie popularyzować inne zasoby informacyjne, które są szczególnie predestynowane do użycia przez użytkowników. Takimi zasobami są zasoby najwyższej jakości. Dlatego w ciele odpowiedzi powinny znaleźć się także dwa dodatkowe linki. Jeden z URI zasobu z tej samej kategorii, drugi z URI zasobu od tego samego dostawcy. W linkach umieszczane są wskazania zasobów o najwyższej jakości, inne niż aktualnie używany. Jeśli nie ma innych zasobów spełniających kryteria linki nie są udostępniane.
Przykład:
Nazwa linku | Objaśnienie |
category-recomended-resource | Link do zasobu informacyjnego najwyższej jakości, z tej samej kategorii co aktualny zasób. |
vendor-recomended-resource | Link do zasobu informacyjnego najwyższej jakości, udostępnianego przez tego samego dostawcę. |
Rekomendacja OD.API
W kontekście linków do nawigacji formułuje się następujące rekomendacje standaryzujące:
- W odpowiedzi na przesyłane przez użytkowników zapytania API udostępnia stany wraz z linkami ułatwiającymi poruszanie się miedzy zasobami powiązanymi. Linki są oznaczane:
- prev (poprzedni),
- self (bieżący),
- next (następny),
- last (ostatni).
- W odpowiedzi na przesyłane przez użytkowników zapytania API udostępnia stany wraz z linkami:
- category-recomended-resource – do zasobu informacyjnego najwyższej jakości, z tej samej kategorii co aktualny zasób,
- vendor-recomended-resource – do zasobu informacyjnego najwyższej jakości, udostępnianego przez tego samego dostawcę.
Wersjonowanie
Wersjonowanie jest jedną z najistotniejszych kwestii do rozważenia przy tworzeniu API. Od tego jak wersjonowanie zostanie zaplanowane i zaimplementowane zależy w przyszłości nie tylko wygoda, ale i możliwość korzystania z API oraz dostępność jego zasobów. Wiele organizacji udostępniających API nie udoskonala go później. Przyczyną często jest nie tyle brak pomysłów na zmiany, co niemożność ich dokonania, gdyż w API nie przewidziano i nie uwzględniono jego ewolucyjnego charakteru. Dlatego OD.API wspiera wersjonowanie API. Zgodnie z REST, nowa wersja API NIE powinna być oznaczona w URI np.
/2/zasoby
Takie oznaczenie powodowałoby, że jeden zasób dostępny jest przez więcej niż jeden identyfikator URI. Zmiana url wprowadzająca oznaczenie wersją np. „2” byłaby możliwa wtedy, gdyby zmianie ulegałaby koncepcja znaczeniowa i relacji zasobów udostępnianych w API. W pozostałych przypadkach należy korzystać z funkcjonalności negocjacji treści udostępnianej przez HTTP[3] zgodnie z RFC 2296. Jeśli klient zażąda określonej wersji – API powinno zwrócić właściwą. Jeśli klient nie wyspecyfikuje konkretnej wersji – API powinno zwrócić aktualną (najnowszą). Nowi użytkownicy będą mogli zatem zapoznać się z bieżącą dokumentacją i korzystać z wersji najnowszej. Dyspozycja będzie mogła być zawarta w nagłówku HTTP o nazwie Accept Header.
Przykład: GET /cepik/pojazdy
Accept: application/vnd.kowalski.user+json; version=2
Dodając nowe funkcjonalności i linki należy dążyć do wstecznej kompatybilności, która nie będzie zakłócała funkcjonalności, z których korzystają dotychczasowi użytkownicy i ich aplikacje. Jeśli kompatybilność wsteczna zostanie zakłócona należy inkrementować wersję.
Numer wersji składa się z trzech liczb:
1.2.1
oddzielonych kropkami, gdzie oznaczenia MAJOR.MINOR.PATCH odpowiadają
- wersję MAJOR, gdy dokonuje się zmian niekompatybilnych z API,
- wersję MINOR, gdy dodaje się nową funkcjonalność, która jest kompatybilna z poprzednimi wersjami,
- wersję PATCH, gdy naprawia się błąd nie zrywając kompatybilności z poprzednimi wersjami.
Jednak do oznaczenia i wywoływania obsługi wersją o konkretnym numerze będzie mieć znaczenie tylko pierwszy człon (MAJOR) wersji, a pozostałe (MINOR i PATCH) będą ignorowane. API powinno wyświetlać numer aktualnie używanej wersji co najmniej w dedykowanej metodzie:
Przykład: GET /ver
Odpowiedź:
{
„api-version”: { „major”: „1”, „minor”: „11”, „patch”: „5”, „date-mod”: „2018-05-20 12:15:30”, }, } |
Odwołanie do wersji API może być wykonane poprzez parametr URI zawierający element MAJOR wersji. Jeśli zawiera pozostałe elementy oznaczenia semantycznego wersji, są one ignorowane.
OD.API umożliwia również odwołanie się do zasobu za pomocą konkretnej wersji poprzez przekazanie parametru „v” w URI. Gdy parametr nie jest podany wykonywane jest odwołanie oryginalne (pierwotne).
Przykład: GET /cepik/pojazdy?v=2
Odpowiedź: Wywołanie reprezentacji zasobu w wersji drugiej.
Należy jednak pamiętać, że wersjonowanie nie jest jedynie kwestią techniczną. Istota modyfikacji API tkwi w celu i zakresie zmian. Zmiany, które są pożądane mogą oddziaływać na API tak dalece, że aplikacje użytkowników po wprowadzeniu zmiany stracą dostęp do dotychczasowych zasobów. Oprócz zarządzania zmianą istotna jest komunikacja z użytkownikami oraz przewidywalność API. Dlatego rozwiązania organizacyjne towarzyszące API powinny zapewniać możliwość komunikowania użytkownikom API zakresu planowanych i wprowadzanych zmian oraz dostarczania informacji nt. przewidywanego okresu działania danej wersji i wsparcia dla API. Spełnienie tego pozwala budować przewidywalne usługi API. Dlatego przed planowaną zmianą wersji należy oznaczyć wersję bieżącą statusem „deprecated” (przestarzałe), który poinformuje dotychczasowych użytkowników, aby nie podejmowali działań w oparciu o tę wersję. Należy zakomunikować ten fakt dotychczasowym użytkownikom oraz określić okres wsparcia, zakończenia wsparcia i zakończenia funkcjonowania bieżącej wersji. Ogłaszany okres zakończenia funkcjonowania wersji nie powinien być krótszy niż dwa lata i należy go dostosować do potrzeb kluczowych użytkowników. W chwili komunikacji zmian użytkownikom powinna być już dostępna dokumentacja dla nowej wersji API, tak aby mogli oni rozpocząć prace nad nowym interfejsem. Po upłynięciu terminu wyłączenia API, powinno ono być jeszcze dostępne przez kwartał, a następnie po wyłączeniu zwracać błąd HTTP 404 (Nie Znaleziono / ang. Not Found), natomiast w ciele błędu powinny się znaleźć objaśnienia nt. wyłączenia API oraz adres nowego interfejsu.
Rekomendacja OD.API
W kontekście wersjonowania API formułuje się następujące rekomendacje standaryzujące:
- Zmiany API oznaczać za pomocą standardu wersjonowania semantycznego API[4],
- Do oznaczenia i wywoływania obsługi wersją o konkretnym numerze ma znaczenie tylko pierwszy człon (MAJOR) wersji, a pozostałe (MINOR i PATCH) są ignorowane zachowując jedynie wartość informacyjną w kontekście wersji interfejsu,
- Dopuszczalne jest odwoływanie się do wersji poprzez parametr URI „v”
- Informację o wersji API należy przekazywać w nagłówkach,
- Jeśli wersja API nie została określona, używa się wersji bieżącej (najnowszej),
- Należy unikać oznaczania wersji w URI, chyba że zmianie ulega semantyka zasobów,
- Przed planowaniem zmiany wersji należy oznaczać wersję bieżącą statusem „deprecated”,
- Nie należy wycofywać obsługi wersji API szybciej niż dwa lata przed powiadomieniem użytkowników.
Obsługa zdarzeń HTTP
OD.API będące tzw. RESTfull API opera się o HyperText Transfer Protocol (HTTP), włączając w to wybrane metody, kody i nagłówki odpowiedzi. OD.API korzysta głownie z metody GET. Nie zakłada się wykorzystania innych niż tzw. bezpieczne metody, tzn. inne niż takie, które mogłyby umożliwiać modyfikację treści zasobów API. HTTP dostarcza pięć kategorii oraz ponad 30 kodów odpowiedzi. Jednak nie wszystkie kody będą w API przydatne, dlatego OD.API przewiduje obsługę wybranych kodów. Poniżej przedstawiono grupy kodów i ich znaczenie[5].
Grupa kodów | Znaczenie | Objaśnienie |
1xx | Informacyjne | Komunikaty transferu na poziomie protokołu. |
2xx | Powodzenie operacji | Wskazuje na powodzenie realizacji żądania klienta. |
3xx | Przekierowanie | Informuje, że do ukończenia żądania klient musi podjąć dodatkową akcję. |
4xx | Błąd klienta | Wskazanie błędu leżącego po stronie klienta |
5xx | Błąd serwera | Wskazanie błędu, za który odpowiada serwer. |
W kolejnej tabeli przedstawiono obsługiwane przez OD.API kody wraz z ich znaczeniem.
Rekomendacja OD.API
W kontekście obsługi zdarzeń HTTP formułuje się następujące rekomendacje standaryzujące:
- Określa się minimalny obsługiwany zestaw kodów odpowiedzi:
Grupa kodów | Znaczenie | Informacja na temat błędu |
2xx | 200 | OK |
201 | Utworzono | |
202 | Zaakceptowano (Accepted) | |
204 | Brak zawartości | |
3xx | 301 | Przeniesiono na stałe |
303 | Zobacz inne | |
304 | Nie modyfikowano | |
4xx | 400 | Błędne żądanie |
401 | Brak autoryzacji | |
403 | Dostęp zabroniony | |
404 | Nie znaleziono | |
405 | Nieodpowiednia metoda | |
409 | Konflikt | |
5xx | 500 | Wewnętrzny błąd serwera |
- Korzysta się z elementu Status-Line w nagłówku HTTP. W przypadku kodu błędów opis uzupełnia się informacją na temat błędów, która powinna być zawarta w ciele odpowiedzi.
Kody z kategorii 4xx i 5xx informują o błędach. Jednak użytkownik nie ma wpływu na błędy z kategorii 5xx gdyż leżą one po stronie serwera. Przy uzyskaniu błędu z kategorii 4xx istnieje prawdopodobieństwo wystąpienia błędów charakterystycznych w określonych sytuacjach. Ranking tych błędów może być tworzony w oparciu o cykliczną analizę logów API. Ranking ten powinien służyć do aktualizacji informacji objaśniających błędy.
Rekomendacja OD.API
W kontekście kodów błędów grupy 4xx formułuje się następujące rekomendacje standaryzujące:
- W ciele odpowiedzi HTTP powinny być zawarte dodatkowe informacje objaśniające:
- Wiadomość objaśniająca rezultat błędu (errorResult),
- Wiadomość objaśniająca przyczynę błędu (errorReason),
- Wiadomość objaśniająca możliwe rozwiązanie (errorSolution),
- Numer błędu (ErrorCode),
- Link do dokumentacji z objaśnieniem numeru błędu dla danej wersji interfejsu (errorHelp).
- Komunikaty powinny być formułowane zgodnie z zasadą S.M.A.R.T
Oznaczenia dodatkowych informacji objaśniających zawarto w tabeli.
Nazwa objaśnienia | Identyfikator objaśnienia |
Wiadomość objaśniająca rezultat błędu | errorResult |
Wiadomość objaśniająca przyczynę błędu | errorReason |
Wiadomość objaśniająca możliwe rozwiązanie | errorSolution |
Kod błędu | ErrorCode |
Link do dokumentacji z objaśnieniem numeru błędu dla danej wersji interfejsu. | errorHelp |
Przykład odpowiedzi w ciele HTTP:
{ „errors”: [ { errorResult: „Przepraszamy, zasób nie istnieje”, errorReason: „Nie znaleziono pojazdu w bazie”, errorSolution: „Id pojazdu powinno być liczbą.” errorCode: 25, errorHelp: „http://dev.danepubliczne.gov.pl/blog/api/2/help/error25” } ] } |
Komunikaty powinny być formułowane zgodnie z zasadą S.M.A.R.T wywodzącą się z nauk ekonomicznych. Przekładając to na grunt komunikatów błędów, muszą one dostarczać konkretnej informacji zwrotnej. Niedopuszczalne są komunikaty, które nie przyczyniają się do rozwiązania problemu przez użytkownika. Oznacza to, że komunikat powinien być:
- sformułowany precyzyjnie w sposób konkretny,
- możliwy do sprawdzania w kontekście przyczynienia się do rozwiązania problemu,
- osiągalny, czyli informacje/zalecenia zawarte w komunikacie powinny być wykonalne przez użytkownika w kontekście informacji, którymi dysponuje,
- wartością dodaną w porównaniu do sytuacji, w której komunikat by nie występował,
- powinien być wykonywalny w akceptowalnym przez użytkownika czasie.
Przykładem komunikatu errorSolution dla kategorii błędów 4xx będzie komunikat zwracający w przypadku przesłanej przez klienta błędnej wartości parametru:
- zakres parametru
- typ parametru
- lista dopuszczonych wartości (jeśli ustalona)
- zapis poprawnego żądania z wykorzystaniem parametru klienta.
Przykład komunikatu S.M.A.R.T dla błędu 404:
{ „errors”: [ { „errorResult”: „Zasób nie może być pobrany”, „errorReason”: „Nie znaleziono zasobu w podanej reprezentacji”, „errorSolution”: „OD.API wersja 1 jest już niedostępna. Konieczna migracja do OD.API w wersji 2. „errorCode”: 95, „errorHelp”: „http://dev.danepubliczne.gov.pl/blog/api/2/help/error95” } ] } |
Uwierzytelnianie i autoryzacja
Uwierzytelnianie użytkownika może być przeprowadzane na wiele sposobów i związane jest z identyfikacją, autentykacją i autoryzacją. Na początku jednak trzeba określić i rozróżnić te pojęcia.
Identyfikacja – identyfikuje użytkownika,
Autentykacja (uwierzytelnianie) – weryfikuje użytkownika, że jest tym za kogo się podaje, innymi słowy nadaje użytkownikowi kontekst,
Autoryzacja – przyznaje uprawnienia do zawartości chronionej np. określonych zasobów API.
Autentykacja może być realizowana za pomocą metody Basic Auth (RFC 2617). Jest to prosty schemat interakcji, w którym podaje się identyfikator użytkownika i hasło, które wcześniej użytkownik uzyskuje rejestrując konto na powiązanej stronie. Wadą tego rozwiązania jest konieczność przesyłania hasła zaszyfrowanego prostą i odwracalną metodą Base64 (RFC 2045). Rozwiązaniem tego problemu jest zastosowanie protokołu HTTPS, który przesłania dane zawarte podczas wymiany informacji.
OAuth 1.0 zdefiniowany przez RFC 5849, jest metodą delegacji uprawnień do zasobów chronionych. Nie jest to standard internetowy w pełnym tego słowa znaczeniu, ale mimo to jest stosowany w zakresie funkcjonalności, które dostarcza. W przypadku stosowania OAut 1.0 API nadaje każdemu użytkownikowi indywidualny zestaw uprawnień. Każdemu użytkownikowi to uprawnienie może być odebrane bez odziaływania na innych użytkowników. OAuth 1.0 jest stosowane do uwierzytelniania klientów, jednak problemy pojawiają się w sytuacji, gdy wymagana jest integracja API z aplikacjami stacjonarnymi bądź mobilnymi lub uruchomionymi wewnątrz przeglądarki. Dlatego OAuth 1.0 w podstawowej wersji nie jest rekomendowane.
Opisane problemy rozwiązuje kolejna wersja OAuth 2.0 (RFC 6749), który nie jest już tylko protokołem, a frameworkiem uwierzytelniania (RFC 6750). OAuth 2.0 jest wyposażony w protokół, którego działanie ma następujący przebieg:
- Klient wysyła do właściciela zasobów żądanie autoryzacyjne. Żądanie autoryzacyjne może być wysłane również metodą pośrednią. W tej metodzie żądanie wysyłane jest poprzez serwer autoryzacji jako pośrednika. Jest to metoda preferowana.
- Właściciel zasobu wysyła do klienta uprawnienie do autoryzacji. Uprawnienie do autoryzacji zależy od używanej przez klienta metody do żądania autoryzacyjnego oraz metod wspieranych przez serwer autoryzacji.
- Klient wysyła do serwera autoryzacji uprawnienie do autoryzacji, uwierzytelnia się i żąda tokena.
- Serwer autoryzujący uwierzytelnia klienta, waliduje uprawnienie do autoryzacji i wysyła do klienta token autoryzujący, gdy uprawnienie i uwierzytelnienie zakończą się pomyślnie.
- Klient przesyła do właściciela zasobów żądanie dostępu do zasobów oraz token autoryzujący.
- Właściciel zasobu waliduje token i jeśli to się powiedzie przesyła klientowi chroniony zasób.
Zaletą takiego podejścia jest unikalna identyfikacja czynności wykonywanych przez konkretnego klienta na zasobach API. W OAuth zewnętrzne aplikacje nie mają styczności z danymi uwierzytelniającymi użytkowników. Dodatkowo tokeny mogą ekspirować po określonym czasie, co pozwala na automatyczne wygaszanie uprawnień klienta API, który w przypadku wygaśnięcia może przejść przez procedurę odświeżenia tokena. W OAuth jeden serwer autoryzacyjny chroni wiele zasobów. Prowadzi to do redukcji kont zakładanych przez użytkowników i posługiwania się w nich często tymi samymi hasłami. Powoduje też, że użytkownicy chętniej podejmują integrację, gdyż jej rozpoczęcie nie wymaga realizowania dodatkowych czynności związanych z zakładaniem nowego konta (co realizuje cel zmniejszania bariery rozpoczęcia pracy z API).
Mimo, że OAuth 2.0 nie jest jeszcze standardem zatwierdzonym przez IETF (status Proposed Standard), to może być on rekomendowany jako pozbawiony wad OAuth w wersji 1.0, oraz dostarczający bardziej kompleksowej funkcjonalności w porównaniu z BasicAuth, ale z zastrzeżeniem o którym mowa w podsumowaniu.
W OAuth 2.0 występują dwa rodzaje tokenów Bearer Token Profile oraz Mac Token Profile. Najbardziej popularnymi są Bearer Token Profile. Jednak Bearer Token jest dowolnym (niesprecyzowanym przez standard) ciągiem znaków i może być odgadnięty przez atakującego metodą brute-force. Dlatego serwer autoryzacyjny musi stosować własne metody zapobiegania brute-force. Zawartość tokena ma znaczenie tylko dla serwera autoryzacyjnego, ale klient i serwer zasobów powinni mieć możliwość walidacji i rozumienia znaczenia.
Protokół OAuth nie jest jednak protokołem autoryzacyjnym[6], gdyż dokonuje jedynie autentykacji. Z tego względu może realizować uwierzytelnienie i stanowić bazę do innych rozwiązań. Zastosowanie czystego OAuth 2.0 do autoryzacji będzie rozwiązaniem błędnym generującym między innymi następujące problemy:
- tokeny będą uznawane w systemie za poświadczenie uwierzytelnienia w systemie, podczas gdy w założeniu OAuth realizuje tylko funkcję delegowania autoryzacji,
- dostęp do chronionego fragmentu staje się dowodem na uwierzytelnienie, a wykorzystanie tokenów na okaziciela (Bearer Tokens) skutkuje możliwością podszycia się pod wybraną tożsamość.
Naprzeciw opisanym wyżej problemom autoryzacji wychodzi OpenID Connect 1.0, które jest prostą warstwą nad OAuth 2.0. OpenID Connect umożliwia weryfikację wykonywaną za pomocą serwera autoryzującego, ale dodatkowo również zapewnia pozyskanie profilu klienta w sposób dedykowany stylowi REST i oparty jest o tokeny JSON Web Token (JWT)[7]. OpenID Connect obsługuje wszystkie rodzaje klientów włączając w to klientów opartych o przeglądarkę, mobilnych czy funkcjonujących bezpośrednio z Javascript. Specyfikacja OpenID Connect jest adaptowalna i rozszerzalna oraz umożliwia obsługę sesji, kiedy jest to konieczne.
Rekomendacja OD.API
W kontekście uwierzytelniania i autoryzacji formułuje się następujące rekomendacje standaryzujące:
- Uwierzytelnianie i autoryzacja użytkowników w API może być oparta o framework OpenID Connect. OpenID zbudowany jest z myślą o wspieraniu architektury REST oraz wymiany informacji w JSON, co wpisuje się w generalne wytyczne OD.API,
- Stosowanie OAuth 2.0. jest dopuszczone, ale w połączeniu z innymi rozwiązaniami wypełniającymi lukę autoryzacji,
- OpenID jest rozwiązaniem wschodzącym, więc może być stosowane uzupełniająco do alternatywnego sposobu OAuth 2.0.,
- W OD.API rekomenduje się stosowanie SSL, a czasie przesyłania danych wrażliwych jest to niezbędne.
Określenie reguł wprowadzania limitów danych per IP
Uzupełniające uwagi w zakresie bezpieczeństwa:
Ograniczanie transferu dla adresów IP powinno być unikane, ale może być stosowane czasowo (z wyjątkiem adresów uznanych za wrogie). Ograniczanie transferu powinno być realizowane w oparciu o ustalone zasady. Należy je opierać o wytyczne teoretyczne oraz faktyczną aktywność użytkowników. W tym celu należy monitorować aktywność API i rozpoznawać typową aktywność użytkowników. Na podstawie tej aktywności konstruować schematy używania API. IP użytkowników wykraczających poza określone schematy, a których aktywność może wpływać na ciągłość usług API, mogą być blokowane, a transfer ograniczany. Blokowanie IP powinno się odbywać przejściowo (z wyjątkiem użytkowników z tzw. czarnych list). Z drugiej strony powinny zostać opracowane tzw. białe listy adresów IP, które mimo, że wykraczają poza normatywne wykorzystanie API mogą eksploatować dalej jego zasoby.
Ograniczenie transferu powinno być w każdym przypadku ostatecznością, a nacisk należy położyć na podnoszenie wydajności API poprzez korzystanie z cache’owania odpowiedzi w celu zmniejszenia obciążenia transferem, kompresję transferu i usprawnienie skalowania.
Rekomendacja OD.API
W kontekście reguł limitów danych formułuje się następujące rekomendacje standaryzujące:
- Interfejs API powinien być zabezpieczony kluczami API i nie dopuszczać niezidentyfikowanego obciążania zasobów API, (także kreator powinien używać zmiennych kluczy).
- Klucze należy przechowywać w zabezpieczonym kryptograficznie sejfie.
- Klucze należy konstruować zgodnie z zasadami konstrukcji tokenów Web JSON.
- Dla API powinna zostać opracowana polityka korzystania z API oraz plany korzystania z API przez użytkowników.
- Powinna być utworzona biała lista użytkowników korzystających z API z priorytetem wyższym niż inni użytkownicy. Reguły wpisu na białą listę powinny być jednoznacznie sformułowane. Dopuszczone jest obciążanie API w sposób wykraczający poza plany obciążeń, szczególnie przez użytkowników z białych list.
- Należy używać reguł dławiących destrukcyjnych użytkowników, w przypadku zagrożenia zablokowaniem API (DOS attack), stosować politykę uznawania adresów IP za wrogie (czarne listy), wykorzystywać zewnętrzne czarne listy[8] do analizy zdarzeń i rozszerzania listy. Posiadać możliwość czasowego i stałego blokowania adresów IP, które uznano za wrogie.
- Transfer może być ograniczamy dla użytkowników gwałtownie zmieniających schemat korzystania z API.
- Transfer może być ograniczamy dla użytkowników generujących transfer i obciążenie zagrażające ciągłości i stabilności API.
- Transfer może być ograniczany dla użytkowników w oparciu o dynamicznie aktualizowane zasady wynikające z analiz faktycznego sposobu korzystania z API przez użytkowników,
- Transfer może być ograniczany dla użytkowników z czarnej listy adresów IP,
- Ograniczenie transferu powinno być w każdym przypadku ostatecznością wynikającą ze stosowania określonych reguł, a nacisk należy położyć na podnoszenie wydajności API.
Opis standardu dokumentacji usług API
Rekomendacja OD.API
W kontekście standardów dokumentacji usług API formułuje się następujące rekomendacje standaryzujące:
Dokumentacja API powinna zawierać co najmniej:
- Opis zasobów. Opis informacji dostarczanej przez każdy zasób, znaczenia zasobu, punktów dostępowych, metod do każdego punktu dostępowego.
- Opis obsługiwanych metod i punktów dostępowych, sposobu dostępu do zasobów, dopuszczonych metod interakcji z zasobami.
- Parametry obsługiwane przez punkt dostępowy w szczególności dotyczące:
- Metody HTTP (GET, POST, PATCH itp.)
- Nagłówków,
- Ścieżki dostępu (URI),
- Parametrów żądania (query)
- Ciała żądania (body) (np.: JSON)
- Przykłady kodu żądań obrazujące użycie złożonych, ale nieskomplikowanych zapytań.
- Przykłady odpowiedzi: struktur i treści przesyłanych klientowi w odpowiedzi na żądania z powyższego punktu.
Ponadto dokumentacja API powinna:
- stosować oznaczenia zapewniające możliwość odczytu maszynowego,
- być dynamiczna i interaktywna,
- automatycznie generować przykłady kodu dla bibliotek klienta.
W zakresie realizacji wytycznych w zakresie dokumentacji oraz uzupełniająco zaleca się stosowanie standardu OpenAPI w obowiązującej obecnie wersji 3.0. lub nowszej.
Na rynku dostępne są narzędzia do generowania dynamicznej i interaktywnej dokumentacji API. Umożliwiają one budowanie kreatorów zapytań do API, a niektóre dedykowane są do współpracy z API typu RESTfull. Do tworzenia dokumentacji zaleca się rozwiązania wspomagające implementację standardu OpenAPI z rodziny rozwiązań Swagger w szczególności Swagger Editor, oraz Swagger UI.
Materiały dodatkowe
Źródła prawa
Dyrektywa 2003/98/WE Parlamentu Europejskiego i Rady z dnia 17 listopada 2003 r. w sprawie ponownego wykorzystywania informacji sektora publicznego (Dz. Urz. UE L 345 z 31.12.2003, str. 90, z późn. zm. – Dz. Urz. UE Polskie wydanie specjalne, rozdz. 13, t. 32, str. 701, z późn. zm.).
Rozporządzenie Rady Ministrów z dnia 12 marca 2014 r. w sprawie Centralnego Repozytorium Informacji Publicznej (Dz. U. poz. 361 z późn. zm.).
Uchwała nr 107/2016 Rady Ministrów z dnia 20 września 2016 r. w sprawie ustanowienia „Programu otwierania danych publicznych”.
Ustawa z dnia 25 lutego 2016 r. o ponownym wykorzystywaniu informacji sektora publicznego (Dz. U. z 2016 r. poz. 352).
Ustawa z dnia 25 lutego 2016 r. o ponownym wykorzystywaniu informacji sektora publicznego (Dz. U. z 2016 r. poz. 352).
Bibliografia
- Fielding „Architectural Styles and the Design of Network-based Software Architectures”, rozprawa doktorska
- Jacobson, D. Woods, APIs. A Strategy Guide, O’Reilly 2012.
- Masse, REST API Design Rulebook: Designing Consistent RESTful Web Service Interfaces, O’Reilly 2012.
- Możejewski „Model pomiaru jakości informacji publicznej na potrzeby ponownego użycia”, rozprawa doktorska.
- Możejewski, Strategia, standaryzacja i pomiar jakości informacji – determinanty efektywnego ponownego wykorzystania informacji sektora publicznego [w:] A. Gołębiowska, P.B. Zientarski (red.), Ponowne wykorzystanie informacji sektora publicznego w administracji, Senat RP, Warszawa 2017.
- Richardsown, M. Amundsen, RESTful Web APIs, O’Reilly 2013.
- Siriwardena, Advanced API Security, Apress.
Standardy techniczne
Schema JSON, http://www.yaml.org/spec/1.2/spec.html#id2803231
REST, R. Fielding „Architectural Styles and the Design of Network-based Software Architectures”, rozprawa doktorska.
ODQM, M. Możejewski „Model pomiaru jakości informacji publicznej na potrzeby ponownego użycia”, rozprawa doktorska.
RFC 2616 – Hypertext Transfer Protocol — HTTP/1.1, http://w3.org/Protocols/rfc2616/rfc2616-sec3.html
RFC 3986, Uniform Resource Identifier (URI): Generic Syntax, https://www.ietf.org/rfc/rfc3986.txt
RFC 1736, Functional Recommendations for Internet Resource Locators, https://tools.ietf.org/html/rfc1736
RFC 1737, Functional Requirements for Uniform Resource Names, https://www.ietf.org/rfc/rfc1737.txt
RFC 2045, Multipurpose Internet Mail Extensions (MIME) Part One: Format of Internet Message Bodies, https://www.ietf.org/rfc/rfc2045.txt
RFC 2296, HTTP Remote Variant Selection Algorithm — RVSA/1.0, https://tools.ietf.org/html/rfc2296
RFC 2617, HTTP Authentication: Basic and Digest Access Authentication, https://www.ietf.org/rfc/rfc2617.txt
RFC 3986, Uniform Resource Identifier (URI): Generic Syntax, https://www.ietf.org/rfc/rfc3986.txt
RFC 5849, The OAuth 1.0 Protocol, https://tools.ietf.org/html/rfc5849
RFC 6749, The OAuth 2.0 Authorization Framework, https://tools.ietf.org/html/rfc6749
RFC 6750, The OAuth 2.0 Authorization Framework: Bearer Token Usage, https://tools.ietf.org/html/rfc6750
RFC 7231, Hypertext Transfer Protocol (HTTP/1.1): Semantics and Content, https://tools.ietf.org/html/rfc7231
[1] Mowa o ustawie z dnia 6 września 2001 r. o dostępie do informacji publicznej (Dz.U. 2001 Nr 112 poz. 1198).
[2] Ustawa z dnia 25 lutego 2016 r. o ponownym wykorzystywaniu informacji sektora publicznego (Dz. U. z 2016 r. poz. 352).
[3] Źródło: RFC 2616.
[4] Zob. https://semver.org/spec/v2.0.0.html [Dostęp 12.02.2018]
[5] Na podstawie RFC 7231.
[6] Zob. https://oauth.net/articles/authentication [Dostęp 12.02.2018]
[7] Zob. Standard JWT dostarczany przez IETF https://tools.ietf.org/html/draft-ietf-oauth-json-web-token-32 [Dostęp 12.02.2018]
[8] Np. http://apility.io [Dostęp 12.02.2018]