Сохранение данных

Способы сохранения данных

ПОМЕЩАТЬ Запись или замена данных по указанному пути , например, fireblog/users/user1/<data>
ПЛАСТЫРЬ Обновить некоторые ключи для заданного пути, не заменяя все данные.
ПОЧТА Добавить данные в список в нашей базе данных Firebase. Каждый раз, когда мы отправляем POST запрос, клиент Firebase генерирует уникальный ключ, например, fireblog/users/<unique-id>/<data>
УДАЛИТЬ Удалить данные из указанной базы данных Firebase.

Запись данных с помощью команды PUT

Основная операция записи через REST API — это PUT . Чтобы продемонстрировать сохранение данных, мы создадим приложение для ведения блога с записями и пользователями. Все данные для нашего приложения будут храниться по пути `fireblog`, по URL-адресу базы данных Firebase `https://docs-examples.firebaseio.com/fireblog`.

Начнём с сохранения данных о пользователях в нашу базу данных Firebase. Мы будем хранить каждого пользователя по уникальному имени пользователя, а также его полное имя и дату рождения. Поскольку у каждого пользователя будет уникальное имя пользователя, здесь имеет смысл использовать PUT вместо POST , так как у нас уже есть ключ, и нам не нужно его создавать.

С помощью PUT мы можем записывать в базу данных Firebase строку, число, логическое значение, массив или любой JSON-объект. В данном случае мы передадим ей объект:

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

При сохранении JSON-объекта в базу данных его свойства автоматически сопоставляются с дочерними элементами вложенным образом. Если мы перейдем к только что созданному узлу, мы увидим значение "Алан Тьюринг". Мы также можем сохранять данные непосредственно в дочерний элемент:

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'

В двух приведенных выше примерах — запись значений одновременно в виде объекта и запись их отдельно в дочерние ячейки — в результате в нашу базу данных Firebase будут сохранены одни и те же данные:

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

Успешный запрос будет обозначен кодом состояния HTTP 200 OK , а ответ будет содержать данные, записанные в базу данных. Первый пример вызовет только одно событие на клиентах, отслеживающих данные, тогда как второй пример вызовет два. Важно отметить, что если данные уже существовали по пути пользователя, первый подход перезапишет их, а второй метод изменит только значение каждого отдельного дочернего узла, оставив другие дочерние узлы без изменений. PUT эквивалентен методу set() в нашем JavaScript SDK.

Обновление данных с помощью PATCH

С помощью запроса PATCH мы можем обновить данные конкретных дочерних элементов в определенном месте, не перезаписывая существующие данные. Давайте добавим никнейм Тьюринга к его пользовательским данным с помощью запроса PATCH :

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

Приведенный выше запрос запишет nickname в наш объект alanisawesome , не удаляя дочерние элементы name и birthday . Обратите внимание, что если бы мы использовали PUT запрос, name и birthday были бы удалены, поскольку они не были включены в запрос. Теперь данные в нашей базе данных Firebase выглядят следующим образом:

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

Успешный запрос будет обозначен HTTP-статусом 200 OK , а ответ будет содержать обновленные данные, записанные в базу данных.

Firebase также поддерживает многопутевые обновления. Это означает, что PATCH теперь может одновременно обновлять значения в нескольких местах вашей базы данных Firebase, что является мощной функцией, помогающей денормализовать ваши данные . Используя многопутевые обновления, мы можем одновременно добавить псевдонимы Алану и Грейс:

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

После этого обновления к Алану и Грейс были добавлены их прозвища:

{
  "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"
    }
  }
}

Обратите внимание, что попытка обновить объекты путем записи объектов с указанием путей приведет к другому поведению. Давайте посмотрим, что произойдет, если мы вместо этого попробуем обновить Грейс и Алана таким способом:

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

Это приводит к другому поведению, а именно к перезаписи всего узла /fireblog/users :

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

Обновление данных с помощью условных запросов

Для обновления данных в соответствии с их текущим состоянием можно использовать условные запросы, REST-аналог транзакций. Например, если вы хотите увеличить счетчик голосов «за» и убедиться, что он точно отражает несколько одновременных голосов «за», используйте условный запрос для записи нового значения в счетчик. Вместо двух операций записи, изменяющих счетчик на одно и то же число, одна из операций записи завершится неудачей, и вы сможете повторить запрос с новым значением.
  1. Для выполнения условного запроса в определенном месте получите уникальный идентификатор текущих данных в этом месте, или ETag. Если данные в этом месте изменяются, ETag также изменяется. Запросить ETag можно любым способом, кроме PATCH . В следующем примере используется запрос GET .
    curl -i 'https://test.example.com/posts/12345/upvotes.json' -H 'X-Firebase-ETag: true'
    Указание параметра ETag в заголовке возвращает ETag указанного местоположения в 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. Включите полученный ETag в следующий запрос PUT или DELETE для обновления данных, которые точно соответствуют этому значению ETag. Следуя нашему примеру, чтобы обновить счетчик до 11, или на 1 больше, чем исходное значение 10, и завершить запрос с ошибкой, если значение больше не соответствует, используйте следующий код:
    curl -iX PUT -d '11' 'https://[PROJECT_ID].firebaseio.com/posts/12345/upvotes.json' -H 'if-match:[ETAG_VALUE]'
    Если значение данных в указанном месте по-прежнему равно 10, то ETag в запросе PUT совпадает, и запрос выполняется успешно, записывая в базу данных значение 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
    Если местоположение больше не соответствует ETag, что может произойти, если другой пользователь записал новое значение в базу данных, запрос завершается с ошибкой, не записав данные в указанное местоположение. В ответе будут указаны новое значение и 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. Используйте новую информацию, если решите повторить запрос. Realtime Database не выполняет автоматическое повторное выполнение условных запросов, которые завершились неудачей. Однако вы можете использовать новое значение и ETag для создания нового условного запроса с информацией, полученной из ответа об ошибке.

Условные запросы на основе REST реализуют стандарт HTTP if-match . Однако они отличаются от стандарта следующим образом:

  • Для каждого запроса if-match можно указать только одно значение ETag, а не несколько.
  • Хотя стандарт предполагает возврат ETags со всеми запросами, база данных Realtime Database возвращает ETags только с запросами, содержащими заголовок X-Firebase-ETag . Это снижает затраты на оплату стандартных запросов.

Условные запросы также могут выполняться медленнее, чем обычные REST-запросы.

Сохранение списков данных

Чтобы сгенерировать уникальный ключ на основе временной метки для каждого дочернего элемента, добавленного в ссылку на базу данных Firebase, мы можем отправить POST запрос. Для путей наших users было логично определить собственные ключи, поскольку у каждого пользователя уникальное имя пользователя. Но когда пользователи добавляют записи в блог в приложение, мы будем использовать POST запрос для автоматической генерации ключа для каждой записи в блоге:

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

Теперь путь к нашим posts содержит следующие данные:

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

Обратите внимание, что ключ -JSOpn9ZC54A4P4RoqVa был сгенерирован автоматически, поскольку мы использовали POST запрос. Успешный запрос будет обозначен кодом состояния HTTP 200 OK , а ответ будет содержать ключ новых добавленных данных:

{"name":"-JSOpn9ZC54A4P4RoqVa"}

Удаление данных

Для удаления данных из базы данных мы можем отправить DELETE запрос с URL-адресом пути, из которого мы хотим удалить данные. Следующий запрос удалит Алана из пути наших users :

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

Успешный запрос DELETE будет обозначен кодом состояния HTTP 200 OK , а ответ будет содержать JSON-значение null .

Параметры URI

REST API принимает следующие URI-параметры при записи данных в базу данных:

аутентификация

Параметр запроса auth обеспечивает доступ к данным, защищенным Firebase Realtime Database Security Rules , и поддерживается всеми типами запросов. Аргументом может быть либо наш секретный ключ приложения Firebase, либо токен аутентификации, которые мы рассмотрим в разделе авторизации пользователя . В следующем примере мы отправляем POST запрос с параметром auth , где CREDENTIAL — это либо наш секретный ключ приложения Firebase, либо токен аутентификации:

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

печать

Параметр print позволяет указать формат ответа от базы данных. Добавление print=pretty к запросу вернет данные в удобочитаемом формате. print=pretty поддерживается запросами GET , PUT , POST , PATCH и DELETE .

Чтобы подавить вывод данных с сервера при записи, можно добавить print=silent к запросу. В результате ответ будет пустым и будет отображаться с кодом состояния HTTP 204 No Content если запрос выполнен успешно. print=silent поддерживается запросами GET , PUT , POST и PATCH .

Запись значений сервера

Значения сервера можно записывать в определенном месте с помощью значения-заполнителя, которое представляет собой объект с одним ключом ".sv" . Значение этого ключа — это тип значения сервера, которое мы хотим установить. Например, чтобы установить метку времени при создании пользователя, мы можем сделать следующее:

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

"timestamp" — единственное поддерживаемое значение сервера, представляющее собой время с начала эпохи UNIX в миллисекундах.

Повышение производительности записи

Если мы записываем большие объемы данных в базу данных, мы можем использовать параметр print=silent для повышения производительности записи и снижения потребления полосы пропускания. В обычном режиме записи сервер отвечает записанными данными в формате JSON. При указании параметра print=silent сервер немедленно закрывает соединение после получения данных, что снижает потребление полосы пропускания.

В случаях, когда мы отправляем много запросов к базе данных, мы можем повторно использовать HTTPS-соединение, отправив запрос Keep-Alive в заголовке HTTP.

Условия возникновения ошибок

В следующих случаях REST API вернет коды ошибок:

Коды состояния HTTP
400 Неверный запрос

Одно из следующих условий ошибки:

  • Не удалось обработать данные PUT или POST .
  • Отсутствуют данные PUT или POST .
  • Запрос пытается отправить данные PUT или POST , но их размер слишком велик.
  • В вызове REST API в пути содержатся недопустимые имена дочерних элементов.
  • Путь вызова REST API слишком длинный.
  • Запрос содержит неопознанное значение сервера.
  • Индекс для запроса не определен в Firebase Realtime Database Security Rules .
  • Запрос не поддерживает один из указанных параметров.
  • В этом запросе сочетаются параметры запроса и неглубокий GET запрос.
401 Несанкционированный доступ

Одно из следующих условий ошибки:

  • Срок действия токена авторизации истек.
  • Использованный в запросе токен аутентификации недействителен.
  • Аутентификация с использованием access_token завершилась неудачей.
  • Данный запрос нарушает Firebase Realtime Database Security Rules .
404 Не найдено Указанная база данных Firebase не найдена.
Ошибка 500 (внутренняя ошибка сервера) Сервер вернул ошибку. Подробности см. в сообщении об ошибке.
Сервис 503 недоступен Указанная база данных Firebase Realtime Database временно недоступна, что означает, что запрос не был предпринят.

Защита данных

В Firebase есть язык безопасности, который позволяет определять, каким пользователям разрешены доступ на чтение и запись к различным узлам наших данных. Подробнее об этом можно прочитать в Realtime Database Security Rules .

Теперь, когда мы рассмотрели сохранение данных, в следующем разделе мы можем узнать, как получать данные из базы данных Firebase через REST API.