Zasada działania Ubera z punktu widzenia użytkownika smartfona jest stosunkowo nieskomplikowana. Uruchamiamy aplikację, wciskamy jeden przycisk i czekamy na kierowcę. Proste? Proste. Ale pójdźmy o krok dalej i zastanówmy się nad nieco bardziej wymagającym użytkownikiem, który chciałby dostać się Uberem w pewne miejsce o zaplanowanej wcześniej godzinie. Po najniższym koszcie. A i żeby sam się zamówił 🙂 Poznajmy Uber API.
Czym jest Uber API?
Uber udostępnił programistom możliwość korzytania we własnych aplikacjach z pełnej funkcjonalności przewozów. Rozmiar API jest dosyć pokaźny, bowiem oprócz funkcji zamawiania umożliwia także szacowanie kosztu kursu, czasu jego trwania, czy ustawienie przypomnienia o planowanym przejeździe. Z technicznego punktu widzenia, jest to w dużej mierze RESTful API, więc nie ma znaczenia z jakiego języka korzystamy przy tworzeniu aplikacji. Przykłady, które pojawią się w tym wpisie będą napisane w języku C#.
Jak zacząć?
1. Do korzystania z Uber API nie potrzebujemy specjalnie rejestrować się jako deweloperzy. Wystarczy do tego klasyczne konto używane do przejazdów.
Jeżeli niniejszy wpis zachęcił Ciebie do zabawy z API, a nie masz jeszcze Uberowego konta, możesz go założyć przy pomocy mojego linku. Dostaniesz wtedy 25 zł do wykorzystania na swój pierwszy przejazd. A po jego realizacji 25 zł dostanę także ja 🙂
2. Przygodę zaczynamy od odwiedzenia strony https://developer.uber.com, gdzie po zalogowaniu zostaniemy przekierowani do okna rejestracji aplikacji. Wpisujemy wymyśloną nazwę, opis i akceptujemy regulamin.
3. Po rejestracji aplikacji spisujemy do późniejszego wykorzystania ID KLIENTA, KLUCZ TAJNY KLIENTA oraz TOKEN SERWERA.
4. W zakładce “Uprawnienia” w polu “Przekieruj Url” wpisujemy “http://localhost”.
5. To w zasadzie wszystko, co jest nam potrzebne, aby zacząć używać Uber API w podstawowym zakresie. W przypadku chęci opublikowania naszej aplikacji i udostępnienia możliwości korzystania z niej przez innych użytkowników – trzeba ustawić jeszcze odpowiednie uprawnienia i złożyć specjalny wniosek o akceptację takiej aplikacji. W tym momencie nie jest to konieczne.
Pytamy o cenę
Jedną z prostszych czynności, jaką możemy wykonać przy użyciu Uber API, jest zapytanie o szacowaną cenę kursu. Do wykonania zapytania będziemy potrzebować zapisany wcześniej TOKEN SERWERA oraz współrzędne geograficzne początku i końca trasy. Pozostaje nam spisać współrzędne z Google Maps, aczkolwiek nic nie stoi na przeszkodzie, aby zaprzęgnąć do tego celu odpowiednie API 🙂 Odsyłam do wpisu Piotra Zielińskiego na ten temat.
Dla ułatwienia analizy przykładów implementacji, w poniższej tabeli znajdują się wartości, które otrzymałem po rejestracji aplikacji.
ID KLIENTA |
---|
atrz29YkWQW0x0D_bgcusMEfS0XPuWPC |
KLUCZ TAJNY KLIENTA |
fWdGq0DLQ9p1n9zVEpTFZ94XSdhTFVmMeCkM8gn5 |
TOKEN SERWERA |
FXMRhfZrWe08yD-mKj7yJMj5ZEv-pUxq6VRfMhdh |
Zapytajmy Ubera, ile kosztowałby kurs spod Dworca Głównego we Wrocławiu (51.098865, 17.036895) do Portu Lotniczego (51.110073, 16.880632).
Adres API pod którym dostaniemy odpowiedź, to:
https://api.uber.com/v1/estimates/price
W przypadku tego zapytania, wystarczy, że wykonamy je metodą GET, dodając do nagłówka TOKEN SERWERA. Oto przykładowy kod, który realizuje to zadanie:
/*...*/ var client = new HttpClient(); client.DefaultRequestHeaders.Add( "Authorization", "Token FXMRhfZrWe08yD-mKj7yJMj5ZEv-pUxq6VRfMhdh"); var queryString = HttpUtility.ParseQueryString(string.Empty); const string uri = "https://api.uber.com/v1/estimates/price"; queryString["start_latitude"] = "51.098865"; queryString["start_longitude"] = "17.036895"; queryString["end_latitude"] = "51.110073"; queryString["end_longitude"] = "16.880632"; var priceEstimation = client.GetStringAsync($"{uri}?{queryString}").Result; /*...*/
W efekcie dostajemy JSONa, z którego dowiadujemy się, że na tej trasie w chwili zapytania zapłacimy w granicach 25-33 zł i pokonamy ją w 1620 sekund:
{ "prices": [{ "localized_display_name": "uberPOP", "high_estimate": 33, "minimum": 8, "duration": 1620, "estimate": "PLN25-33", "distance": 8.23, "display_name": "uberPOP", "product_id": "2bc02557-7c84-4a21-88bd-261dd5b3a816", "low_estimate": 25, "surge_multiplier": 1.0, "currency_code": "PLN" }] }
Nie jest to coś, czego nie jesteśmy w stanie sami sprawdzić korzystając z aplikacji na smartfona. Jednak przy pomocy API możemy pytać i pytać i pytać w nieskończoność, co pozwoli na zbadanie pewnych prawidłowości na tej trasie i zaplanowanie w przyszłości kursu w taki sposób, aby uniknąć pory, w której jest drożej.
Zapytajmy jeszcze kilka razy
Pozwoliłem sobie popytać Ubera kilka tysięcy razy przez całą dobę, ile kosztowałby powyższy kurs (request wysyłany średnio raz na 3 sekundy). Na pierwszy rzut oka można wyciągnąć pewne wnioski, a już na pewno będzie ich więcej, jeśli przebadamy daną trasę np. przez cały miesiąc dzień w dzień. Jak widać, są takie pory, w których bardziej może opłacić się zamówić klasyczną taksówkę, ale również takie, w których to Uber będzie zdecydowanie tańszy. Poniżej wykres przedstawiający jak cena przejazdu z Dworca Głównego we Wrocławiu do Portu Lotniczego kształtowała się w sobotę 2016-07-23 od 00:00 do 23:59. Jeżeli ktoś planuje szarpnąć się na codzienne dojazdy do pracy Uberem, warto zrobić sobie taką analizę i dobrać godziny dojazdów tak, aby najbardziej zoptymalizować ten koszt 🙂 Nie do końca wiem jak wygląda to z punktu widzenia kierowców, ale przeanalizowanie miasta pod kątem najbardziej dochodowych godzin i miejsc wydaje się być sensowne.
Zanim zamówimy przejazd
Zamawianie przejazdów w imieniu użytkownika (a nawet w swoim imieniu) wymaga uzykania odpowiednich uprawnień. API Ubera używa do tego celu standardu autoryzacji OAuth 2.0. W naszym przypadku sprowadza się to do wygenerowania odpowiedniego tokena, który będzie dołączany do każdego nagłówka zapytania.
W celu wygenerowania tokena użytkownika, należy wykonać poniższe kroki:
1. Akceptujemy zamawianie przejazdów w naszym imieniu
Aby uzyskać odpowiednie uprawnienia, musimy przygotować specjalne zapytanie bazując na:
https://login.uber.com/oauth/v2/authorize
Do powyższego adresu należy dodać trzy parametry:
– client_id – który już wcześniej poznaliśmy
– scope=request – parametr oznaczający, że prosimy o uprawnienia do zamawiania przewozów w naszym imieniu
– response_type=code – bez tego parametru nie działa, a nie może on też przyjąć innej wartości. Jest bo jest 🙂
Po uwzględnieniu powyższch punktów, adres, który należy odwiedzić przy pomocy przeglądarki wygląda następująco:
https://login.uber.com/oauth/v2/authorize?client_id=atrz29YkWQW0x0D_bgcusMEfS0XPuWPC&scope=request&response_type=code
Po zalogowaniu i zaakceptowaniu uprawnień do zamawiania przejazdów zostaniemy przekierowani na adres zawierający odpowiedni kod. W tym też celu przy konfiguracji aplikacji wpisywaliśmy adres przekierowania. Właśnie w tym momencie adres ten jest wykorzystywany.
W moim przypadku zaakceptowanie uprawnień przekierowało mnie na stronę:
http://localhost/?code=wFab2iFcVpkVp1U0Lr7gRvtxDzxwK6#_
To jeszcze nie koniec całego procesu, bowiem dopiero otrzymany kod możemy zamienić na token 🙂
2. Wymieniamy kod na token
Na tym etapie, gdy już mamy kod, do wygenerowania tokena posłużymy się poniższym przykładem:
/*...*/ var client = new HttpClient(); const string uri = "https://login.uber.com/oauth/v2/token"; var content = new List<KeyValuePair<string, string>> { new KeyValuePair<string, string>( "client_secret", "fWdGq0DLQ9p1n9zVEpTFZ94XSdhTFVmMeCkM8gn5"), new KeyValuePair<string, string>( "client_id", "atrz29YkWQW0x0D_bgcusMEfS0XPuWPC"), new KeyValuePair<string, string>( "grant_type", "authorization_code"), new KeyValuePair<string, string>( "redirect_uri", "http://localhost"), new KeyValuePair<string, string>( "code", "wFab2iFcVpkVp1U0Lr7gRvtxDzxwK6#_") }; var requestContent = new FormUrlEncodedContent(content); var requestResult = client.PostAsync(uri, requestContent).Result; var resultContent = requestResult.Content.ReadAsStringAsync().Result; /*...*/
Samo zapytanie polega na wysłaniu pod adres https://login.uber.com/oauth/v2/token metodą POST kod, który otrzymaliśmy w wyniku autoryzacji i reszty danych identyfikujących naszą aplikację.
Po ciężkich bojach 🙂 w odpowiedzi przychodzi do nas JSON zawierający wszystko co potrzebne, aby zacząć zamawiać kurs:
{ "last_authenticated": 1469560074, "access_token": "BARDZO_DLUGI_ACCESS_TOKEN", "expires_in": 2592000, "token_type": "Bearer", "scope": "request", "refresh_token": "LsQwzAsXyJt4QfVGshFhhQm8JgxbX7" }
Wygenerowanym tokenem możemy posługiwać się przez 30 dni. Traci ważność w momencie, w którym wygenerujemy użytkownikowi ponownie token dla danej aplikacji lub go odświeżymy przy pomocy tokenu odświeżającego “refresh_token”.
Zamawiamy UBERa!
Po przekopaniu podstawowych zasad rządzących Uber API jesteśmy gotowi do zamówienia kursu przy pomocy naszej aplikacji. Zanim będziemy w pełni gotowi do wykonywania rzeczywistych zamówień – aby nie ponieść niepotrzebnych kosztów – możemy skorzystać ze środowiska testowego. Adres API w przypadku środowiska testowego ma adres https://sandbox-api.uber.com. Wszystkie wygenerowane do tej pory tokeny działają zarówno w środowisku produkcyjnym jak i testowym.
Adres Uber API, który służy do składania zamówień to:
https://api.uber.com/v1/requests
Całość zamówienia sprowadza się do wywołania powyższego adresu metodą POST z tokenem w nagłówku oraz lokalizacją źródłową i docelową jako argumenty zapytania (tym razem dane, które wysyłamy muszą być reprezentowane JSONem). I możemy ruszać w podróż 🙂
Pozostaje jeszcze sprawa sprawdzenia statusu zamówienia. W tym celu metodą GET z tokenem w nagłówku wywołujemy poniższy adres:
https://api.uber.com/v1/requests/current
Implementacja zamawiania pojazdu może wyglądać następująco:
/*...*/ var client = new HttpClient(); client.DefaultRequestHeaders.Add( "Authorization", "Bearer BARDZO_DLUGI_ACCESS_TOKEN"); const string uri = "https://api.uber.com/v1/requests"; dynamic content = new { start_latitude = "51.098865", start_longitude = "17.036895", end_latitude = "51.110073", end_longitude = "16.880632" }; var jsonContent = JsonConvert.SerializeObject(content); var requestContent = new StringContent(jsonContent); requestContent.Headers.ContentType = new MediaTypeHeaderValue("application/json"); var requestResult = client.PostAsync(uri, requestContent).Result; var resultContent = requestResult.Content.ReadAsStringAsync().Result; /*...*/
Zaś sprawdzania statusu aktualnie odbywanego przejazdu w sposób poniższy:
/*...*/ var client = new HttpClient(); client.DefaultRequestHeaders.Add( "Authorization", "Bearer BARDZO_DLUGI_ACCESS_TOKEN"); const string uri = "https://api.uber.com/v1/requests/current"; var status = client.GetStringAsync(uri).Result; /*...*/
Testujemy!
Aby nie pozostać jedynie przy teorii całego procesu, postanowiłem sprawdzić działanie Uber API na żywym organiźmie. W tym celu, po przejściu całej procedury uzyskiwania tokena, złożyłem zamówienie, ustawiłem sprawdzanie statusu co 5 sekund i udałem się na wyznaczone przeze mnie miejsce odbioru. Chwilę niepewności rozwiała wiadomość sms, którą po chwili otrzymałem:
Your Uber is on the way.
Edward (4.9 stars) will arrive in 6 minutes.
Poniżej fragmenty statusów, jakie zalogowała aplikacja podczas całego procesu mojego przejazdu:
22:09:42 {"status":"processing" /*...*/ } 22:09:53 {"status":"accepted","destination":{ "eta":12 /*...*/ }} /*...*/ 22:15:54 {"status":"in_progress","destination":{ "eta":7 /*...*/ }} /*...*/ 22:23:15 {"status":"in_progress","destination":{ "eta":1 /*...*/ }} 22:23:21 {"status":"in_progress","destination":{ "eta":0 /*...*/ }}
Co ciekawe, zaraz po realizacji kursu, status przestaje być dostępny, a serwer w odpowiedzi zwraca kod 404:
Response status code does not indicate success: 404 (no_current_trip).
Tytułem zakończenia
Uber API daje nam ciekawe możliwości, których nie oferuje klasyczna aplikacja dostępna na smartfona. Możemy pokusić się o analizę danych, czy zamawianie przejazdu według ustalonego harmonogramu – wiele pomysłów na wykorzystanie API nasuwa się na myśl. Przedstawione tutaj przykłady to jedynie garstka z dostępnego publicznie API. Zachęcam do próbowania i dzielenia się pomysłami na jego wykorzystanie 🙂
Jeżeli niniejszy wpis zachęcił Ciebie do zabawy z API, a nie masz jeszcze Uberowego konta, możesz go założyć przy pomocy mojego linku. Dostaniesz wtedy 25 zł do wykorzystania na swój pierwszy przejazd. A po jego realizacji 25 zł dostanę także ja 🙂
P.S. Pan Edward nie poparł pomysłu polowania na czas i miejsce podwyższonego mnożnika – podobno większość klientów czeka, aż mnożnik spadnie, podczas gdy kierowcy Ubera stoją na postojach.
Przygotowując wpis, korzystałem z dokumentacji Uber API dostępnej pod adresem https://developer.uber.com/docs/rides