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

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

ПОМЕЩАТЬ Запишите или замените данные по указанному пути , например 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 , мы можем записать строку, число, логическое значение, массив или любой JSON-объект в базу данных Firebase. В данном случае мы передадим ей объект:

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

При сохранении JSON-объекта в базе данных свойства объекта автоматически сопоставляются с дочерними расположениями во вложенном порядке. Если перейти к только что созданному узлу, мы увидим значение «Alan Turing». Мы также можем сохранить данные непосредственно в дочернем расположении:

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, а не несколько.
  • Хотя стандарт предполагает возврат ETag со всеми запросами, Realtime Database возвращает ETag только с запросами, содержащими заголовок 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 временно недоступна, что означает, что запрос не был выполнен.

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

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

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