Salvar dados

Como salvar dados

PUT Grave ou substitua dados em um caminho definido, como fireblog/users/user1/<data>
PATCH Atualize algumas chaves de um caminho específico sem substituir todos os dados.
POST Adicione a uma lista de dados do banco de dados do Firebase. Sempre que uma solicitação POST é enviada, o cliente do Firebase gera uma chave exclusiva, como fireblog/users/<unique-id>/<data>
DELETE Remova os dados da referência especificada de banco de dados do Firebase.

Gravar dados com PUT

A operação básica de gravação por meio da API REST é PUT. Para demonstrar a economia de dados, criaremos um aplicativo de blog com postagens e usuários. Todos os dados do aplicativo serão armazenados no caminho do "fireblog", no URL do banco de dados do Firebase "https://docs-examples.firebaseio.com/fireblog".

Vamos começar salvando alguns dados de usuário no banco de dados do Firebase. Armazenaremos cada usuário com base em um nome de usuário exclusivo, além do nome completo e data de nascimento. Como cada um terá um nome de usuário exclusivo, utilizaremos PUT em vez de POST, porque já temos a chave e não precisaremos criar outra.

O PUT grava uma string, um número, um booleano, uma matriz ou qualquer objeto JSON no banco de dados do Firebase. Neste caso, transferiremos um objeto:

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

Quando um objeto JSON é salvo no banco de dados, as propriedades dele são automaticamente mapeadas nos locais filhos, de maneira aninhada. Depois de navegar até o nó recém-criado, veremos o valor "Alan Turing". Também podemos salvar os dados diretamente em um local filho:

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'

Nos dois exemplos acima (gravar o valor e o objeto ao mesmo tempo e gravá-los separadamente nos locais filhos), os mesmos dados são salvos no banco de dados do Firebase:

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

Um código de status HTTP 200 OK indica que uma solicitação foi bem-sucedida e que a resposta contém os dados gravados no banco de dados. O primeiro exemplo só aciona um evento nos clientes que estão monitorando os dados, enquanto o segundo aciona dois. É importante observar que a primeira abordagem substitui os dados existentes no caminho dos usuários. No entanto, o segundo método apenas modifica o valor de cada nó filho, deixando os demais filhos inalterados. O PUT é equivalente a set() no SDK para JavaScript.

Atualizar dados com PATCH

Uma solicitação PATCH atualiza filhos específicos em um local sem substituir os dados já existentes. Vamos adicionar o apelido de Alan Turing aos dados de usuário com uma solicitação PATCH:

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

A solicitação acima gravará nickname em nosso objeto alanisawesome sem excluir os filhos name ou birthday. Se tivéssemos emitido uma solicitação PUT aqui, name e birthday seriam excluídos porque não foram incluídos na solicitação. Os dados no nosso banco de dados do Firebase agora aparecem assim:

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

Um código de status HTTP 200 OK indica que uma solicitação foi bem-sucedida e que a resposta contém os dados atualizados gravados no banco de dados.

O Firebase também faz atualizações em vários caminhos. Ou seja, agora o PATCH pode atualizar valores em vários locais simultaneamente no banco de dados do Firebase. Esse é um recurso bastante eficiente para desnormalizar seus dados. Com as atualizações em vários caminhos, é possível adicionar apelidos a Alan e Grace simultaneamente:

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

Após essa atualização, os apelidos de Alan e Grace serão adicionados:

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

Se fizer isso gravando os objetos com os caminhos incluídos, o comportamento será diferente. Vejamos o que acontece quando tentamos atualizar Grace e Alan desta forma:

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

O resultado será um comportamento diferente, ou seja, todo o nó /fireblog/users será substituído:

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

Como atualizar dados com solicitações condicionais

Você pode usar solicitações condicionais, que equivalem ao REST em transações, para atualizar dados de acordo com o estado existente. Por exemplo, se você quiser aumentar um contador de votos e verificar se a contagem reflete com precisão vários votos simultâneos, use uma solicitação condicional para gravar o novo valor no contador. Em vez de duas gravações que alteram o contador para o mesmo número, uma das solicitações de gravação é definida como falha. Então, você pode tentar uma nova solicitação com o novo valor.
  1. Para executar uma solicitação condicional em um local, encontre o identificador exclusivo para os dados atuais nesse local, ou a ETag. Se os dados mudarem nesse local, a ETag também será alterada. É possível solicitar uma ETag com qualquer método diferente de PATCH. O exemplo a seguir usa uma solicitação GET.
    curl -i 'https://test.example.com/posts/12345/upvotes.json' -H 'X-Firebase-ETag: true'
    
    Chamar especificamente a ETag no cabeçalho retorna a ETag do local especificado na resposta 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. Inclua a ETag retornada na sua próxima solicitação PUT ou DELETE para atualizar dados que correspondem especificamente ao valor ETag. Seguindo nosso exemplo, para atualizar o contador para 11, ou 1 maior que o valor inicial buscado de 10, e falhar a solicitação se o valor não corresponder mais, use o seguinte código:
    curl -iX PUT -d '11' 'https://[PROJECT_ID].firebaseio.com/posts/12345/upvotes.json' -H 'if-match:[ETAG_VALUE]'
    
    Se o valor dos dados no local especificado ainda for 10, a ETag na solicitação PUT corresponderá e a solicitação será bem-sucedida, gravando 11 no banco de dados.
    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
    
    Se o local não corresponder mais à ETag, o que pode ocorrer se outro usuário gravar um novo valor no banco de dados, a solicitação falhará sem gravar no local. A resposta de retorno inclui o novo valor e a 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. Use as novas informações para repetir a solicitação. O Realtime Database não repete automaticamente as solicitações condicionais que falharam. No entanto, você pode usar o novo valor e a ETag para criar uma nova solicitação condicional com a informação retornada pela resposta de falha.

As solicitações condicionadas baseadas em REST implementam o padrão HTTP if-match. No entanto, eles diferem do padrão das seguintes maneiras:

  • Você só pode fornecer um valor ETag para cada solicitação if-match.
  • Embora o padrão sugira que as ETags sejam retornadas com todas as solicitações, o Realtime Database retorna apenas ETags com solicitações, incluindo o cabeçalho X-Firebase-ETag. Isso reduz os custos de cobrança para solicitações padrão.

Solicitações condicionais também podem ser mais lentas do que solicitações REST comuns.

Salvar listas de dados

Para gerar uma chave exclusiva baseada em carimbo de data/hora para cada filho adicionado a uma referência de banco de dados do Firebase, podemos enviar uma solicitação POST. Para nosso caminho users, faz sentido definir nossas próprias chaves, já que cada usuário tem um nome de usuário exclusivo. No entanto, quando os usuários adicionarem postagens de blog ao app, usaremos uma solicitação POST para gerar automaticamente uma chave para cada postagem:

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

Agora, o caminho posts tem os seguintes dados:

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

A chave -JSOpn9ZC54A4P4RoqVa foi gerada automaticamente porque usamos uma solicitação POST. Um código de status HTTP 200 OK indica que a solicitação foi bem-sucedida e que a resposta contém a chave dos novos dados adicionados:

{"name":"-JSOpn9ZC54A4P4RoqVa"}

Remover dados

Para remover dados do banco de dados, envie uma solicitação DELETE com o URL do caminho dos dados a serem excluídos. Alan seria excluído do nosso caminho users da seguinte maneira:

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

Uma solicitação DELETE bem-sucedida será indicada por um código de status HTTP 200 OK com uma resposta contendo null de JSON.

Parâmetros de URI

A REST API aceita os seguintes parâmetros de URI ao gravar dados no banco de dados:

auth

Com o parâmetro de solicitação auth, é possível acessar os dados protegidos pelas regras de segurança do Firebase Realtime Database. Além disso, ele é compatível com todos os tipos de solicitação. O argumento pode ser a chave secreta do app do Firebase ou um token de autenticação, que será abordado na seção sobre autorização do usuário. No exemplo a seguir, enviamos uma solicitação POST com um parâmetro auth, em que CREDENTIAL é a chave secreta do app do Firebase ou um token de autenticação:

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

print

O parâmetro print permite especificar o formato da nossa resposta do banco de dados. Adicionar print=pretty à nossa solicitação retornará os dados em um formato legível. print=pretty é compatível com as solicitações GET, PUT, POST, PATCH e DELETE.

Para suprimir a saída do servidor ao gravar dados, podemos adicionar print=silent à solicitação. A resposta resultante estará vazia e indicada por um código de status HTTP 204 No Content se a solicitação for bem-sucedida. O print=silent é compatível com solicitações GET, PUT, POST e PATCH.

Gravar valores de servidor

Os valores do servidor podem ser gravados em um local usando um valor de marcador, que é um objeto com uma única chave ".sv". O valor dessa chave é o tipo de valor de servidor a ser definido. Por exemplo, para definir um carimbo de data/hora na criação de um usuário, faça o seguinte:

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

"timestamp" é o único valor de servidor compatível e é o tempo desde a época do UNIX em milissegundos.

Como melhorar o desempenho de gravação

Para gravar grandes quantidades de dados no banco de dados, podemos usar o parâmetro print=silent para melhorar nosso desempenho de gravação e diminuir o uso da largura de banda. Em condições normais de gravação, o servidor responde com os dados JSON gravados. Quando print=silent é especificado, o servidor fecha imediatamente a conexão assim que os dados são recebidos, reduzindo o uso da largura de banda.

Ao fazer muitas solicitações para o banco de dados, reutilize a conexão HTTPS e envie uma solicitação Keep-Alive para o cabeçalho HTTP.

Condições de erro

A REST API retornará códigos de erro nestas circunstâncias:

Códigos de status HTTP
400 Solicitação inválida

Uma das seguintes condições de erro:

  • Não é possível analisar dados do PUT ou do POST.
  • Os dados do PUT ou do POST estão ausentes.
  • A solicitação tenta executar PUT ou POST em dados muito extensos.
  • A chamada de API REST contém nomes de filhos inválidos como parte do caminho.
  • O caminho da chamada à REST API é muito longo.
  • A solicitação contém um valor de servidor não reconhecido.
  • O índice para a consulta não foi definido nas regras de segurança do Firebase Realtime Database.
  • A solicitação é incompatível com um dos parâmetros de consulta especificados.
  • A solicitação combina parâmetros de consulta com uma solicitação GET superficial.
401 Não autorizado

Uma das seguintes condições de erro:

404 Não encontrado O banco de dados do Firebase especificado não foi encontrado.
500 Erro interno do servidor O servidor retornou um erro. Consulte a mensagem de erro para mais detalhes.
503 Serviço não disponível O Firebase Realtime Database especificado está temporariamente indisponível, o que significa que não houve tentativa de solicitação.

Proteção de dados

O Firebase tem uma linguagem de segurança para definir quais usuários têm acesso de leitura e gravação aos diferentes nós dos dados. Confira mais informações em Regras de segurança do Realtime Database.

Agora você já sabe como salvar dados. Na próxima seção aprenderemos a recuperá-los do banco de dados do Firebase com a API REST.