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ą PUT

Podstawową operacją zapisu za pomocą interfejsu 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 naszej 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ć PUT tutaj zamiast POST, ponieważ mamy już klucz i nie musimy go tworzyć.

Za pomocą PUT możemy zapisać w bazie danych Firebase ciąg znaków, liczbę, wartość logiczną, tablicę lub dowolny obiekt JSON do naszej bazy danych Firebase. 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 – zapisanie wartości jednocześnie z obiektem i zapisanie 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 będzie świadczyć 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ą PATCH

Za pomocą żądania PATCH możemy aktualizować określone węzły 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 węzłów podrzędnych name ani birthday. Pamiętaj, że gdybyśmy zamiast tego wysłali żądanie PUT, węzły 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 będzie świadczyć 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 denormalizować dane. 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 mieć pewność, że liczba ta dokładnie odzwierciedla wiele jednoczesnych głosów, 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 w bazie danych nową wartość, żą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 się nie powiodły. 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 REST 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 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 węzła 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 będą dodawać 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 będzie świadczyć 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 z naszej users ścieżki:

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

O pomyślnym żądaniu DELETE będzie świadczyć kod stanu HTTP 200 OK z odpowiedzią zawierającą 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 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 będzie o niej świadczyć kod stanu HTTP 204 No Content. print=silent jest obsługiwany przez żądania GET, PUT, POST i PATCH.

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ścią tego klucza jest typ wartości serwera, którą chcemy ustawić. Aby na przykład ustawić sygnaturę czasową utworzenia 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 węzłó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ą 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.