Zapisywanie danych

Sposoby zapisywania danych

PUT Zapisywanie lub zastępowanie danych w określonej ścieżce, np. fireblog/users/user1/<data>
PATCH Aktualizowanie niektórych kluczy w określonej ścieżce bez zastępowania wszystkich danych.
POST Dodawanie 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Ń Usuwanie danych z określonego odwołania do bazy danych Firebase.

Zapisywanie danych za pomocą metody PUT

Podstawową operacją zapisu w interfejsie REST API jest PUT. Aby zademonstrować zapisywanie 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 danych użytkownika w bazie danych Firebase. Każdego użytkownika będziemy przechowywać pod unikalną nazwą użytkownika, a także jego pełne imię i nazwisko oraz datę urodzenia. Ponieważ każdy użytkownik będzie miał unikalną nazwę użytkownika, warto użyć tutaj metody PUT zamiast POST, ponieważ mamy już klucz i nie musimy go tworzyć.

Za pomocą metody PUT możemy zapisać w bazie danych Firebase ciąg znaków, liczbę, wartość logiczną, tablicę lub dowolny obiekt JSON. W tym przypadku przekażemy 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, właściwości obiektu są automatycznie mapowane na lokalizacje podrzędne w sposób zagnieżdżony. 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'

Dwa powyższe przykłady – zapisywanie wartości jednocześnie z obiektem i zapisywanie ich oddzielnie w lokalizacjach podrzędnych – spowodują zapisanie tych samych danych w naszej bazie danych Firebase:

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

O pomyślnym żądaniu poinformuje kod stanu HTTP 200 OK, a odpowiedź będzie zawierać dane, które zapisaliśmy w bazie danych. Pierwszy przykład spowoduje tylko 1 zdarzenie u klientów, którzy obserwują dane, a drugi – 2. Pamiętaj, że jeśli w ścieżce użytkowników istniały już dane, pierwsze podejście spowoduje ich zastąpienie, ale druga metoda zmodyfikuje tylko wartość każdego oddzielnego węzła podrzędnego pozostawiając inne węzły podrzędne bez zmian. PUT jest odpowiednikiem set() w naszym pakiecie JavaScript SDK.

Aktualizowanie danych za pomocą metody PATCH

Za pomocą żądania PATCH możemy aktualizować określone elementy podrzędne w lokalizacji bez zastępowania istniejących danych. Dodajmy pseudonim Turinga do jego danych użytkownika za pomocą żądania PATCH:

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

Powyższe żądanie zapisze nickname w naszym obiekcie alanisawesome bez usuwania elementów podrzędnych name ani birthday. Pamiętaj, że gdybyśmy zamiast tego wysłali żądanie PUT, elementy name i birthday zostałyby usunięte, ponieważ nie zostały uwzględnione w żądaniu. 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"
    }
  }
}

O pomyślnym żądaniu poinformuje kod 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 pozwala na denormalizację danych. Za pomocą aktualizacji wielościeżkowych możemy jednocześnie dodać pseudonimy do Alana i Grace:

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

Po tej aktualizacji zarówno Alan, jak i Grace mają dodane pseudonimy:

{
  "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 aktualizacji obiektów przez zapisywanie obiektów ze ścieżkami spowoduje inne zachowanie. 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'

Spowoduje to inne zachowanie, 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

Żądania warunkowe, które są odpowiednikiem transakcji w interfejsie REST API, umożliwiają aktualizowanie danych zgodnie z ich obecnym stanem. Jeśli na przykład chcesz zwiększyć licznik głosów na „tak” i upewnić się, że liczba ta dokładnie odzwierciedla wiele jednoczesnych głosów na „tak”, użyj żądania warunkowego, aby zapisać nową wartość w liczniku. Zamiast 2 zapisów, które zmieniają licznik na tę samą liczbę, jedno z żądań zapisu nie powiedzie się, a Ty możesz ponowić żądanie z nową wartością.
  1. Aby wykonać żądanie warunkowe w lokalizacji, pobierz unikalny identyfikator bieżących danych w tej lokalizacji lub ETag. Jeśli dane w tej lokalizacji się zmienią, zmieni się też ETag. Możesz poprosić o ETag za pomocą dowolnej metody innej niż PATCH. W tym przykładzie używamy żą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ślonej lokalizacji w odpowiedzi HTTP.
    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. Dołącz zwrócony ETag do następnego PUT lub DELETE żądania, aby zaktualizować dane, które dokładnie pasują do tej wartości ETag. W naszym przykładzie, aby zaktualizować licznik do 11 (czyli o 1 więcej niż początkowa pobrana wartość 10) i odrzucić żądanie, jeśli wartość nie będzie już pasować, 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ślonej lokalizacji nadal wynosi 10, ETag w żądaniu PUT pasuje, a żądanie się powiedzie, zapisując w bazie danych wartość 11.
    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 się zdarzyć, gdy inny użytkownik zapisze nową wartość w bazie danych, żądanie nie powiedzie się bez zapisywania w lokalizacji. Odpowiedź zwrotna 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ę ponowić żądanie, użyj nowych informacji. Realtime Database nie ponawia automatycznie żądań warunkowych, które nie powiodły się. Możesz jednak użyć nowej wartości i ETag, aby utworzyć nowe żądanie warunkowe z informacjami zwróconymi przez odpowiedź o niepowodzeniu.

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

  • W przypadku każdego żądania if-match możesz podać tylko 1 wartość ETag, a nie kilka.
  • Standard sugeruje, aby ETagi były zwracane ze wszystkimi żądaniami, ale baza danych czasu rzeczywistego zwraca ETagi tylko w przypadku żądań zawierających X-Firebase-ETag nagłówek. Zmniejsza to koszty rozliczeniowe w przypadku standardowych żądań.

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

Zapisywanie list danych

Aby wygenerować unikalny klucz oparty na sygnaturze czasowej 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 warto było zdefiniować własne klucze, ponieważ każdy użytkownik ma unikalną nazwę użytkownika. Gdy jednak użytkownicy dodają posty na blogu do aplikacji, użyjemy żądania POST aby automatycznie wygenerować klucz dla każdego posta:

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

Nasza ś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 request. O pomyślnym żądaniu poinformuje kod stanu HTTP 200 OK, a odpowiedź będzie zawierać klucz dodanych nowych 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. Poniższe polecenie usunie Alana ze ścieżki users

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

O pomyślnym żądaniu DELETE poinformuje kod stanu HTTP 200 OK, a odpowiedź będzie zawierać wartość JSON null.

Parametry URI

Podczas zapisywania danych w bazie danych interfejs REST API akceptuje te parametry URI:

autoryzacja

Parametr żądania auth umożliwia dostęp do danych chronionych przez Firebase Realtime Database Security Rules i jest obsługiwany przez wszystkie typy żądań. Argumentem może być tajny klucz aplikacji w Firebase lub token uwierzytelniania, o którym opowiemy w sekcji dotyczącej autoryzacji użytkownika. W tym przykładzie wysyłamy żądanie POST z parametrem auth, gdzie CREDENTIAL to tajny klucz aplikacji w Firebase lub token uwierzytelniania:

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 print=pretty do żądania spowoduje zwrócenie danych w formacie czytelnym dla człowieka. print=pretty jest obsługiwany przez żądania GET, PUT, POST, PATCH i DELETE.

Aby pominąć dane wyjściowe z serwera podczas zapisywania danych, możemy dodać print=silent do żądania. Jeśli żądanie się powiedzie, odpowiedź będzie pusta i oznaczona kodem stanu HTTP 204 No Content. print=silent jest obsługiwany przez GET, PUT, POST i PATCH żądania.

Zapisywanie wartości serwera

Wartości serwera można zapisywać w lokalizacji za pomocą wartości zastępczej, która jest obiektem z pojedynczym ".sv" kluczem. Wartość tego klucza to typ wartości serwera, którą chcemy ustawić. Aby na przykład ustawić sygnaturę czasową podczas tworzenia użytkownika, możemy zrobić tak:

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 początku epoki uniksowej .

Zwiększanie wydajności zapisu

Jeśli zapisujemy w bazie danych duże ilości danych, możemy użyć parametru print=silent aby zwiększyć wydajność zapisu i zmniejszyć zużycie przepustowości. W przypadku normalnego zapisu serwer odpowiada zapisanymi danymi JSON. Gdy print=silent jest określony, serwer natychmiast zamyka połączenie po otrzymaniu danych, co zmniejsza zużycie przepustowości.

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

Warunki błędu

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

Kody stanów HTTP
400 Nieprawidłowe żądanie

Jeden z tych warunków błędu:

  • Nie można przeanalizować danych PUT ani POST.
  • Brak danych PUT lub POST.
  • Żądanie próbuje PUT lub POST danych, które jest zbyt duże.
  • Wywołanie interfejsu API typu REST zawiera nieprawidłowe nazwy elementów podrzędnych jako część ścieżki.
  • Ścieżka wywołania interfejsu API (typu) 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 warunków błędu:

  • Token autoryzacji wygasł.
  • Token autoryzacji użyty w żądaniu jest nieprawidłowy.
  • Nie udało się uwierzytelnić za pomocą tokena access_token.
  • Żądanie narusza reguły bezpieczeństwa bazy danych Firebase Realtime Database. Firebase Realtime Database Security Rules.
404 Nie znaleziono Nie udało się znaleźć określonej 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 Określona Baza danych czasu rzeczywistego Firebase jest tymczasowo niedostępna, co oznacza, że żądanie nie zostało podjęte.

Zabezpieczanie danych

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

Teraz, gdy omówiliśmy zapisywanie danych, w następnej sekcji dowiesz się, jak pobierać dane z bazy danych Firebase za pomocą interfejsu REST API.