Zapisywanie danych

Sposoby oszczędzania danych

PUT zapisywać lub zastępować dane w określonej ścieżce, np. fireblog/users/user1/<data>
PATCH zaktualizować niektóre klucze na zdefiniowanej ścieżce 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ą metody PUT

Podstawową operacją zapisu w interfejsie API REST jest PUT. Aby zademonstrować zapisywanie danych, utworzymy aplikację do blogowania z wpisami 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 niektórych danych użytkownika do bazy danych Firebase. Każdego użytkownika będziemy przechowywać pod unikalną nazwą użytkownika. Będziemy też przechowywać 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 wywoła tylko jedno zdarzenie na klientach, którzy obserwują dane, a drugi – dwa. Pamiętaj, że jeśli dane są już dostępne na ścieżce użytkowników, pierwsze podejście zastąpi je, ale drugie zmodyfikuje tylko wartość każdego osobnego węzła podrzędnego, pozostawiając inne bez zmian. Zmienna PUT jest odpowiednikiem zmiennej set() w pakiecie JavaScript SDK.

Aktualizowanie danych za pomocą 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łalibyś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"
    }
  }
}

Pomyślne żądanie będzie oznaczone 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 aktualizować wartości w różnych miejscach w bazie danych Firebase jednocześnie. Ta potężna funkcja ułatwia denormalizację danych. Dzięki aktualizacjom wielościeżkowym możemy dodać przezwiska do Alana 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 zamiast tego 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'

Spowoduje to inne działanie, a mianowicie zastąpienie całego węzła /fireblog/users:

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

Aktualizowanie danych za pomocą żądań warunkowych

Aby zaktualizować dane zgodnie z ich obecnym stanem, możesz użyć żądań warunkowych, które są odpowiednikiem REST dla transakcji. 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 przypadku lokalizacji, pobierz unikalny identyfikator bieżących danych w tej lokalizacji lub tag E. 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. W tym przykładzie użyto żą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 podaj zwrócony identyfikator 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 niż początkowa wartość pobrana z 10, oraz odrzucić żądanie, jeśli wartość nie jest już zgodna, 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 określonym miejscu jest nadal 10, znacznik ETag w żądaniuPUT jest zgodny, a żądanie się powiedzie, co spowoduje zapisanie 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 tagu ETag, co może się zdarzyć, gdy inny użytkownik zapisze nową wartość w bazie danych, żądanie nie zostanie zrealizowane, a dane nie zostaną zapisane w 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ń z nagłówkiem X-Firebase-ETag. Pozwala to obniżyć koszty rozliczeń za żądania standardowe.

Żądania warunkowe mogą też być wolniejsze niż typowe żądania REST.

Zapisywanie list danych

Aby wygenerować unikalny klucz oparty na sygnaturze czasową dla każdego elementu podrzędnego dodanego do odwołania 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 z bloga, użyjemy żądania POST, aby automatycznie wygenerować klucz dla każdego z nich:

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. Pomyślne żądanie zostanie oznaczone 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 identyfikatora URI

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

uwierzytelnienie

Parametr 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 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ługiwana przez żądania 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 zastępczej, która jest obiektem z jednym kluczem ".sv". Wartość tego klucza to typ wartości serwera, który chcemy ustawić. Aby np. ustawić sygnaturę czasową podczas tworzenia użytkownika, możesz 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.

Zwiększanie 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 przypadku zwykłego zapisu serwer odpowiada danymi JSON, które zostały zapisane. Gdy określona jest wartość print=silent, serwer natychmiast zamyka połączenie po otrzymaniu danych, co zmniejsza wykorzystanie przepustowości.

W przypadku wysyłania wielu żądań do bazy danych możemy ponownie 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 próbuje PUT lub POST danych, które są za duże.
  • Wywołanie interfejsu API REST zawiera nieprawidłowe nazwy podrzędnych jako część ścieżki.
  • Ścieżka wywołania interfejsu API REST jest zbyt 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 miesza parametry zapytania z płytkim żądaniem GET.
401 Brak autoryzacji

Jeden z tych błędów:

  • Token uwierzytelniania wygasł.
  • Token uwierzytelniający 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 Wybrana baza danych czasu rzeczywistego Firebase jest tymczasowo niedostępna, co oznacza, że żądanie nie zostało wysłane.

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.