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, 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 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 nadpisze 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 przesłać żądanie z nową wartością.
  1. Aby wykonać żądanie warunkowe w danej 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 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 ETaga, co może się zdarzyć, gdy inny użytkownik zapisze nową wartość w bazie danych, żądanie nie powiedzie się, 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. Żądanie zakończone powodzeniem zostanie oznaczone kodem stanu HTTP 200 OK, a odpowiedź będzie zawierać klucz nowych dodanych danych:

{"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 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 umożliwia określenie formatu 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.

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 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 w składowej ś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 określonych parametrów zapytania.
  • Żądanie łączy 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 Wskazana 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.