Zapisywanie danych

Sposoby oszczędzania danych

PUT zapisywać lub zastępować dane w określonej ścieżce, np. fireblog/users/user1/<data>
PATCH Zaktualizuj niektóre klucze zdefiniowanej ścieżki bez zastępowania wszystkich danych.
POST Dodaj do listy danych w naszej bazie danych Firebase. Za każdym razem, gdy wysyłamy żądanie POST, klient Firebase generuje unikalny klucz, np. fireblog/users/<unique-id>/<data>
USUŃ Usuń dane z określonej bazy danych Firebase.

Zapisywanie danych za pomocą PUT

Podstawową operacją zapisu w interfejsie API REST jest PUT. Aby zademonstrować oszczędzanie danych, utworzymy aplikację do blogowania z postami i użytkownikami. Wszystkie dane naszej aplikacji będą przechowywane w ścieżce „fireblog” pod adresem URL bazy danych Firebase „https://docs-examples.firebaseio.com/fireblog”.

Zacznijmy od zapisania w bazie danych Firebase części danych użytkowników. Każdego użytkownika będziemy przechowywać pod unikalną nazwą użytkownika, a także jego imię i nazwisko oraz datę urodzenia. Ponieważ każdy użytkownik ma niepowtarzalną nazwę użytkownika, warto użyć tutaj parametru PUT zamiast POST, ponieważ klucz już mamy i nie trzeba go tworzyć.

Za pomocą funkcji PUT możemy zapisywać w naszej bazie danych Firebase ciągi tekstowe, liczby, wartości logiczne, tablice i dowolne obiekty JSON. W tym przypadku przekazujemy obiekt:

curl -X PUT -d '{
  "alanisawesome": {
    "name": "Alan Turing",
    "birthday": "June 23, 1912"
  }
}' 'https://docs-examples.firebaseio.com/fireblog/users.json'

Gdy obiekt JSON jest zapisywany w bazie danych, jego właściwości są automatycznie mapowane na pozycje podrzędne w postaci zagnieżdżonej. Jeśli przejdziesz do nowo utworzonego węzła, zobaczysz wartość „Alan Turing”. Możemy też zapisywać dane bezpośrednio w lokalizacji podrzędnej:

curl -X PUT -d '"Alan Turing"' \
  'https://docs-examples.firebaseio.com/fireblog/users/alanisawesome/name.json'
curl -X PUT -d '"June 23, 1912"' \
  'https://docs-examples.firebaseio.com/fireblog/users/alanisawesome/birthday.json'

Opisane powyżej 2 przykłady – zapisywanie wartości w tym samym czasie co obiekt i oddzielnie w miejscach podrzędnych – spowodują zapisanie tych samych danych w bazie danych Firebase:

{
  "users": {
    "alanisawesome": {
      "date_of_birth": "June 23, 1912",
      "full_name": "Alan Turing"
    }
  }
}

Pomyślne żądanie będzie oznaczone kodem stanu HTTP 200 OK, a odpowiedź będzie zawierać dane zapisane w bazie danych. Pierwszy przykład spowoduje wywołanie tylko 1 zdarzenia na klientach, którzy obserwują dane, a drugi – 2 zdarzeń. Warto zauważyć, że jeśli dane istniały już na ścieżce użytkownika, pierwsze podejście spowodowałoby ich zastąpienie, natomiast druga metoda jedynie zmodyfikuje wartość każdego oddzielnego węzła podrzędnego, a pozostałe węzły podrzędne pozostaną niezmienione. PUT jest odpowiednikiem set() w naszym pakiecie JavaScript SDK.

Aktualizowanie danych za pomocą parametru PATCH

Dzięki żądaniu PATCH możemy zaktualizować informacje o konkretnych dzieciach w danej lokalizacji bez nadpisywania dotychczasowych danych. Dodajmy do danych użytkownika pseudonim Turinga za pomocą żądania PATCH:

curl -X PATCH -d '{
  "nickname": "Alan The Machine"
}' \
  'https://docs-examples.firebaseio.com/fireblog/users/alanisawesome.json'

Powyższe żądanie spowoduje zapisanie wartości nickname w obiekcie alanisawesome bez usuwania elementów podrzędnych name ani birthday. Jeśli zamiast tego wysłaliśmy prośbę PUT, treści namebirthday zostałyby usunięte, ponieważ nie zostały uwzględnione w prośbie. Dane w naszej bazie danych Firebase wyglądają teraz tak:

{
  "users": {
    "alanisawesome": {
      "date_of_birth": "June 23, 1912",
      "full_name": "Alan Turing",
      "nickname": "Alan The Machine"
    }
  }
}

Udane żądanie będzie sygnalizowane kodem stanu HTTP 200 OK, a odpowiedź będzie zawierać zaktualizowane dane zapisane w bazie danych.

Firebase obsługuje też aktualizacje wielościeżkowe. Oznacza to, że PATCH może teraz jednocześnie aktualizować wartości w wielu lokalizacjach w bazie danych Firebase. Jest to zaawansowana funkcja, która pomaga denormalizować dane. Dzięki aktualizacjom na wielu ścieżkach możemy dodawać pseudonimy zarówno Alanowi, jak i Grace jednocześnie:

curl -X PATCH -d '{
  "alanisawesome/nickname": "Alan The Machine",
  "gracehopper/nickname": "Amazing Grace"
}' \
  'https://docs-examples.firebaseio.com/fireblog/users.json'

Po tej aktualizacji dodano do niego pseudonimy Alana i Grace:

{
  "users": {
    "alanisawesome": {
      "date_of_birth": "June 23, 1912",
      "full_name": "Alan Turing",
      "nickname": "Alan The Machine"
    },
    "gracehop": {
      "date_of_birth": "December 9, 1906",
      "full_name": "Grace Hopper",
      "nickname": "Amazing Grace"
    }
  }
}

Pamiętaj, że próba zaktualizowania obiektów przez zapisanie obiektów z dołączonymi ścieżkami spowoduje inne działanie. Zobaczmy, co się stanie, jeśli spróbujemy zaktualizować Grace i Alana w ten sposób:

curl -X PATCH -d '{
  "alanisawesome": {"nickname": "Alan The Machine"},
  "gracehopper": {"nickname": "Amazing Grace"}
}' \
  'https://docs-examples.firebaseio.com/fireblog/users.json'

Powoduje to inne zachowanie, czyli zastępowanie całego węzła /fireblog/users:

{
  "users": {
    "alanisawesome": {
      "nickname": "Alan The Machine"
    },
    "gracehop": {
      "nickname": "Amazing Grace"
    }
  }
}

Aktualizowanie danych za pomocą żądań warunkowych

Do aktualizowania danych zgodnie z obecnym stanem możesz używać żądań warunkowych, które są odpowiednikiem transakcji typu REST. Jeśli na przykład chcesz zwiększyć liczbę głosów za i upewnić się, że odzwierciedla ona prawidłowo liczbę głosów za jednocześnie, użyj warunkowego żądania, aby zapisać nową wartość w liczniku. Zamiast 2 zapisań, które zmieniają licznik na tę samą wartość, jeden z tych zapisów zakończy się niepowodzeniem, a potem możesz ponownie wykonać żądanie z nową wartością.
  1. Aby wykonać żądanie warunkowe w danej lokalizacji, pobierz unikalny identyfikator bieżących danych w tej lokalizacji lub ETag. Jeśli dane w tej lokalizacji ulegną zmianie, zmieni się też ETag. Możesz poprosić o E-Tag za pomocą dowolnej metody innej niż PATCH. Poniższy przykład korzysta z żądania GET.
    curl -i 'https://test.example.com/posts/12345/upvotes.json' -H 'X-Firebase-ETag: true'
    Wywołanie ETag w nagłówku zwraca ETag określonego w odpowiedzi HTTP miejsca.
    HTTP/1.1 200 OK
    Content-Length: 6
    Content-Type: application/json; charset=utf-8
    Access-Control-Allow-Origin: *
    ETag: [ETAG_VALUE]
    Cache-Control: no-cache
    
    10 // Current value of the data at the specified location
  2. W następnym żądaniu PUT lub DELETE uwzględnij zwrócony tag ETag, aby zaktualizować dane, które pasują do tej wartości. W naszym przykładzie, aby zaktualizować licznik do 11 lub o 1 większy od początkowej wartości pobranej 10, a także odrzucić żądanie, jeśli wartość nie pasuje, użyj tego kodu:
    curl -iX PUT -d '11' 'https://[PROJECT_ID].firebaseio.com/posts/12345/upvotes.json' -H 'if-match:[ETAG_VALUE]'
    Jeśli wartość danych w wybranej lokalizacji nadal wynosi 10, tag ETag w żądaniuPUT pasuje do siebie, a żądanie się powiedzie, zapisując 11 do bazy danych.
    HTTP/1.1 200 OK
    Content-Length: 6
    Content-Type: application/json; charset=utf-8
    Access-Control-Allow-Origin: *
    Cache-Control: no-cache
    
    11 // New value of the data at the specified location, written by the conditional request
    Jeśli lokalizacja nie pasuje już do ETag, co może wystąpić, gdy inny użytkownik zapisze nową wartość w bazie danych, żądanie zakończy się niepowodzeniem bez zapisywania danych lokalizacji. Odpowiedź zawiera nową wartość i ETag.
    HTTP/1.1 412 Precondition Failed
    Content-Length: 6
    Content-Type: application/json; charset=utf-8
    Access-Control-Allow-Origin: *
    ETag: [ETAG_VALUE]
    Cache-Control: no-cache
    
    12 // New value of the data at the specified location
  3. Jeśli zdecydujesz się ponownie przesłać prośbę, użyj nowych informacji. Realtime Databasenie próbuje automatycznie ponownie wysyłać żądań warunkowych, które zakończyły się niepowodzeniem. Możesz jednak użyć nowej wartości i ETag, aby utworzyć nowe żądanie warunkowe z informacjami zwróconymi przez odpowiedź na błąd.

Żądania warunkowe oparte na protokole REST implementują standard HTTP if-match. Różnią się jednak od standardowych w tych kwestiach:

  • W przypadku każdego żądania if-match możesz podać tylko 1 wartość ETag, a nie kilka.
  • Chociaż standard zaleca zwracanie tagów ETag ze wszystkimi żądaniami, Realtime Database zwraca je tylko w przypadku żądań zawierających nagłówek X-Firebase-ETag. Pozwala to obniżyć koszty rozliczeń za żądania standardowe.

Żądania warunkowe mogą też działać wolniej niż typowe żądania REST.

Zapisywanie list danych

Aby wygenerować unikalny, oparty na sygnaturze czasowej klucz dla każdego elementu podrzędnego dodanego do odniesienia do bazy danych Firebase, możemy wysłać żądanie POST. W przypadku ścieżki users sensowne było zdefiniowanie własnych kluczy, ponieważ każdy użytkownik ma unikalną nazwę użytkownika. Gdy jednak użytkownicy dodadzą do aplikacji posty na blogu, użyjemy żądania POST do automatycznego wygenerowania klucza dla każdego posta na blogu:

curl -X POST -d '{
  "author": "alanisawesome",
  "title": "The Turing Machine"
}' 'https://docs-examples.firebaseio.com/fireblog/posts.json'

Ścieżka posts zawiera teraz te dane:

{
  "posts": {
    "-JSOpn9ZC54A4P4RoqVa": {
      "author": "alanisawesome",
      "title": "The Turing Machine"
    }
  }
}

Zwróć uwagę, że klucz -JSOpn9ZC54A4P4RoqVa został wygenerowany automatycznie, ponieważ użyliśmy żądania POST. Żądanie zakończone powodzeniem będzie sygnalizowane kodem stanu HTTP 200 OK, a odpowiedź będzie zawierać klucz nowych danych, które zostały dodane:

{"name":"-JSOpn9ZC54A4P4RoqVa"}

Usuwanie danych

Aby usunąć dane z bazy danych, możemy wysłać żądanie DELETE z adresem URL ścieżki, z której chcemy usunąć dane. Zmiana ta spowoduje usunięcie Alana z ścieżkiusers:

curl -X DELETE \
  'https://docs-examples.firebaseio.com/fireblog/users/alanisawesome.json'

Pomyślne żądanie DELETE będzie sygnalizowane przez kod stanu HTTP 200 OK z odpowiedzią zawierającą dane JSON null.

Parametry URI

Podczas zapisywania danych do bazy danych interfejs REST API akceptuje te parametry URI:

uwierzytelnienie

Parametr żądania auth umożliwia dostęp do danych chronionych przez Firebase Realtime Database Security Rules i jest obsługiwany przez wszystkie typy żądań. Argument może być tajnym kluczem aplikacji Firebase lub tokenem uwierzytelniania, o którym piszemy w sekcji autoryzacja użytkownika. W tym przykładzie wysyłamy żądanie POST z parametrem auth, gdzie CREDENTIAL to nasz obiekt tajny aplikacji Firebase lub token uwierzytelniający:

curl -X POST -d '{"Authenticated POST request"}' \
  'https://docs-examples.firebaseio.com/auth-example.json?auth=CREDENTIAL'

drukuj

Parametr print pozwala nam określić format odpowiedzi z bazy danych. Dodanie parametru print=pretty do żądania spowoduje, że dane zostaną zwrócone w formacie zrozumiałym dla człowieka. print=pretty jest obsługiwany w przypadku żądań GET, PUT, POST, PATCH i DELETE.

Aby podczas zapisywania danych nie wyświetlać danych wyjściowych z serwera, możemy dodać do naszej prośby parametrprint=silent. Jeśli żądanie zostanie zrealizowane, odpowiedź będzie pusta i będzie oznaczona kodem stanu HTTP 204 No Content. print=silent jest obsługiwana przez żądania GET, PUT, POSTPATCH.

Zapisywanie wartości serwera

Wartości serwera można zapisywać w lokalizacji za pomocą wartości zmiennej, która jest obiektem z jednym kluczem ".sv". Wartość tego klucza to typ wartości serwera, który chcemy ustawić. Aby na przykład ustawić sygnaturę czasową tworzenia użytkownika, możemy wykonać te czynności:

curl -X PUT -d '{".sv": "timestamp"}' \
  'https://docs-examples.firebaseio.com/alanisawesome/createdAt.json'

"timestamp" to jedyna obsługiwana wartość serwera. Jest to czas w milisekundach od epoki UNIX.

Poprawianie wydajności zapisu

Jeśli do bazy danych zapisujemy duże ilości danych, możemy użyć parametru print=silent, aby zwiększyć wydajność zapisu i zmniejszyć wykorzystanie przepustowości. W normalnym trybie zapisu serwer odpowiada, przesyłając zapisane dane JSON. Gdy określona jest wartość print=silent, serwer natychmiast zamyka połączenie po otrzymaniu danych, co zmniejsza wykorzystanie przepustowości.

Jeśli otrzymujemy wiele żądań do bazy danych, możemy użyć połączenia HTTPS, wysyłając żądanie Keep-Alive w nagłówku HTTP.

Warunki błędu

Interfejs REST API zwraca kody błędów w tych okolicznościach:

Kody stanu HTTP
400 Nieprawidłowe żądanie

Jeden z tych błędów:

  • Nie udało się przeanalizować danych PUT ani POST.
  • Brak danych PUT lub POST.
  • Żądanie ma na celu próbę PUT lub POST danych, które są zbyt duże.
  • Wywołanie interfejsu API REST zawiera nieprawidłowe nazwy elementów podrzędnych w ścieżce.
  • Ścieżka wywołania interfejsu API REST jest za długa.
  • Żądanie zawiera nierozpoznaną wartość serwera.
  • Indeks zapytania nie jest zdefiniowany w Firebase Realtime Database Security Rules.
  • Żądanie nie obsługuje jednego z wybranych parametrów zapytania.
  • Żądanie łączy parametry zapytania z płytkim żądaniem GET.
401 Brak autoryzacji

Jeden z tych warunków błędu:

  • Token uwierzytelniania wygasł.
  • Token uwierzytelniania użyty w żądaniu jest nieprawidłowy.
  • Nie udało się uwierzytelnić za pomocą tokena dostępu.
  • Prośba narusza Twoje Firebase Realtime Database Security Rules.
404 Nie znaleziono Nie udało się znaleźć wskazanej bazy danych Firebase.
500 – wewnętrzny błąd serwera Serwer zwrócił błąd. Więcej informacji znajdziesz w komunikacie o błędzie.
503 Usługa niedostępna Podana Baza danych czasu rzeczywistego Firebase jest tymczasowo niedostępna, co oznacza, że nie podjęto próby wykonania żądania.

Zabezpieczanie danych

Firebase ma język bezpieczeństwa, który pozwala nam określać, którzy użytkownicy mają dostęp do odczytu i zapisu do różnych węzłów danych. Więcej informacji znajdziesz w artykule Realtime Database Security Rules.

W następnej sekcji dowiesz się, jak pobierać dane z bazy danych Firebase za pomocą interfejsu REST API.