Guarda datos

Maneras de guardar datos

COLOCAR Escribe o reemplaza datos en una ruta de acceso definida, como fireblog/users/user1/<data>
PATCH Actualiza algunas de las claves de una ruta de acceso definida, sin reemplazar todos los datos.
PUBLICAR Agrega a una lista de datos en la base de datos de Firebase. Cada vez que enviamos una solicitud POST, el cliente de Firebase genera una clave única, como fireblog/users/<unique-id>/<data>.
BORRAR Quita datos desde la referencia especificada en la base de datos de Firebase.

Escribe datos con PUT

La operación de escritura básica que se realiza a través de la API de REST es PUT. Para demostrar el ahorro de datos, compilaremos una aplicación de blog que cuenta con entradas y usuarios. Todos los datos de nuestra aplicación se almacenarán en la ruta de acceso “fireblog”, en la URL de la base de datos de Firebase, “https://docs-examples.firebaseio.com/fireblog”.

Comencemos por guardar parte de los datos de usuarios en nuestra base de datos de Firebase. Almacenaremos cada usuario con un nombre de usuario único junto con su nombre completo y su fecha de nacimiento. Debido a que cada usuario tendrá un nombre de usuario único, tiene sentido usar PUT en este caso, en lugar de POST, debido a que ya tenemos la clave y no necesitamos crear otra.

Con PUT, podemos escribir una string, un número, un valor booleano, un arreglo o cualquier objeto JSON en nuestra base de datos de Firebase. En este caso, le pasaremos un objeto:

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

Cuando se guarda un objeto JSON en la base de datos, las propiedades de este se asignan automáticamente a ubicaciones secundarias de forma anidada. Si navegamos al nodo recién creado, veremos el valor “Alan Turing”. También podemos guardar datos directamente en una ubicación secundaria:

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'

En los dos ejemplos anteriores (escribir el valor al mismo tiempo que un objeto y escribir ambos por separado en ubicaciones secundarias), se guardarán los mismos datos en nuestra base de datos de Firebase.

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

Si la solicitud se procesa correctamente, recibiremos un código de estado HTTP 200 OK y la respuesta contendrá los datos que escribimos en la base de datos. En el primer ejemplo, solo se activará un evento en clientes que observen los datos, mientras que en el segundo se activarán dos. Es importante tener en cuenta que, si los datos ya existían en la ruta de acceso de los usuarios, el primer ejemplo los reemplazará, pero el segundo método solo cambiará el valor de cada nodo secundario por separado y no cambiará los otros elementos secundarios. PUT es equivalente a set() en nuestro SDK de JavaScript.

Actualiza datos con PATCH

A través de una solicitud PATCH, podemos actualizar elementos secundarios específicos en una ubicación sin reemplazar los datos existentes. Agreguemos el apodo de Turing a sus datos de usuario con una solicitud de tipo PATCH:

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

La solicitud anterior escribirá nickname en nuestro objeto alanisawesome sin borrar los elementos secundarios name o birthday. Ten en cuenta que si hubiéramos emitido una solicitud PUT en este caso, name y birthday se habrían borrado, ya que no se incluyeron en la solicitud. Los datos en nuestra base de datos de Firebase ahora se ven de la siguiente manera:

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

Si la solicitud se procesa correctamente, recibiremos un código de estado HTTP 200 OK y la respuesta contendrá los datos que actualizamos en la base de datos.

Firebase también admite actualizaciones en varias rutas de acceso. Esto significa que PATCH ahora puede actualizar valores en varias ubicaciones de la base de datos de Firebase a la vez, una función potente que te permite desnormalizar los datos. Las actualizaciones en varias rutas de acceso permiten agregar apodos a Alan y Grace al mismo tiempo:

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

Después de esta actualización, se agregaron apodos a Alan y Grace:

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

Ten en cuenta que, si intentas actualizar objetos escribiéndolos con las rutas de acceso incluidas, se generará un comportamiento diferente. Veamos lo que sucede si en lugar de esto intentamos actualizar los datos de Grace y de Alan de la siguiente manera:

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

Esto genera un comportamiento diferente; en particular, se reemplaza el nodo /fireblog/users:

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

Actualiza datos con solicitudes condicionales

Puedes usar las solicitudes condicionales, que son el equivalente de REST a las transacciones, para actualizar los datos según su estado actual. Por ejemplo, si deseas aumentar un recuento de votos a favor y quieres asegurarte de que refleje con exactitud los múltiples votos a favor simultáneos, usa una solicitud condicional para escribir el valor nuevo del contador. En lugar de que se ejecuten dos operaciones de escritura que cambien el contador al mismo número, una de las solicitudes de escritura falla y puedes volver a ejecutar la solicitud con el nuevo valor.
  1. Para realizar una solicitud condicional en una ubicación, obtén el identificador único de los datos actuales en esa ubicación o la ETag. Si los datos cambian en esa ubicación, la ETag también cambiará. Puedes solicitar una ETag con cualquier método que no sea PATCH. En el siguiente ejemplo, se usa una solicitud GET.
    curl -i 'https://test.example.com/posts/12345/upvotes.json' -H 'X-Firebase-ETag: true'
    
    La llamada específica a la ETag en el encabezado muestra la ETag de la ubicación especificada en la respuesta 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. Incluye la ETag que se muestra en tu siguiente solicitud PUT o DELETE para actualizar los datos que coincidan específicamente con el valor de esa ETag. En el mismo ejemplo, para actualizar el contador a 11, o a 1 punto más que el valor de 10 que se recuperó al inicio, y hacer fallar la solicitud si el valor ya no coincide, usa el siguiente código:
    curl -iX PUT -d '11' 'https://[PROJECT_ID].firebaseio.com/posts/12345/upvotes.json' -H 'if-match:[ETAG_VALUE]'
    
    Si el valor de los datos en la ubicación especificada sigue siendo 10, la ETag en la solicitud PUT coincidirá y la solicitud será correcta, de manera que se escribirá 11 en la base de datos.
    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
    
    Si la ubicación ya no coincide con la ETag, lo cual podría ocurrir si otro usuario escribió un valor nuevo en la base de datos, la solicitud fallará y no se escribirá en la ubicación. La respuesta incluirá el valor nuevo y la 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. Usa la nueva información si decides volver a ejecutar la solicitud. Realtime Database no lo reintenta automáticamente con las solicitudes condicionales que fallaron. Sin embargo, puedes usar el valor nuevo y la ETag para generar una nueva solicitud condicional con la información que muestra la respuesta de error.

Las solicitudes condicionales basadas en REST implementan el estándar de HTTP if-match. Sin embargo, son diferentes al estándar en estos aspectos:

  • Únicamente puedes proporcionar un valor de ETag, y no varios, por cada solicitud if-match.
  • Aunque el estándar sugiere que se muestren las ETags con todas las solicitudes, Realtime Database muestra solamente ETags con las solicitudes que incluyen el encabezado X-Firebase-ETag. De esta manera, se reducen los costos de facturación de las solicitudes estándares.

Las solicitudes condicionales también podrían ser más lentas que las solicitudes de REST típicas.

Guarda listas de datos

Si queremos generar una clave única basada en una marca de tiempo para cada campo secundario agregado a una referencia de la base de datos de Firebase, podemos enviar una solicitud de tipo POST. Para nuestra ruta de acceso de users, tiene sentido definir nuestras propias claves, dado que cada usuario tiene un nombre de usuario único. Sin embargo, cuando los usuarios agreguen entradas de blogs a la app, usaremos una solicitud POST a fin de generar de forma automática una clave para cada entrada de blog:

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

Ahora, nuestra ruta de acceso de posts tiene los siguientes datos:

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

Ten en cuenta que la clave -JSOpn9ZC54A4P4RoqVa se generó de forma automática, porque usamos una solicitud POST. Una solicitud correcta mostrará un código de estado HTTP 200 OK y la respuesta contendrá la clave de los datos nuevos que se agregaron:

{"name":"-JSOpn9ZC54A4P4RoqVa"}

Quita datos

Para quitar datos de la base de datos, podemos enviar una solicitud de tipo DELETE con la URL de la ruta de acceso de la que queremos borrar datos. En el siguiente ejemplo, se borraría a Alan de nuestra ruta de acceso de users:

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

Si la solicitud DELETE se realiza correctamente, recibiremos un código de estado HTTP 200 OK con una respuesta que contiene JSON null.

Parámetros de URI

La API de REST acepta los siguientes parámetros URI cuando se escribe en la base de datos:

auth

El parámetro de solicitud auth permite acceder a los datos protegidos por Firebase Realtime Database Security Rules y es compatible con todos los tipos de solicitud. El argumento puede ser el secreto de tu app de Firebase o un token de autenticación, como se describe en más detalle en la sección de autorización de usuarios. En el siguiente ejemplo, enviamos una solicitud POST con un parámetro auth, en el que CREDENTIAL es el secreto de tu app de Firebase o un token de autenticación:

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

imprimir

El parámetro print nos permite especificar el formato de nuestra respuesta desde la base de datos. Si agregamos print=pretty a nuestra solicitud, se mostrarán los datos en un formato legible. print=pretty es compatible con las solicitudes GET, PUT, POST, PATCH y DELETE.

Para suprimir el resultado del servidor cuando se escriben datos, podemos agregar print=silent a nuestra solicitud. La respuesta resultante estará vacía y se indicará con un código de estado HTTP 204 No Content si la solicitud se completó correctamente. print=silent es compatible con las solicitudes GET, PUT, POST y PATCH.

Escribe valores de servidor

Los valores de servidor se pueden escribir en una ubicación con un valor de marcador de posición, que es un objeto con una sola clave ".sv". El valor de esta clave es el tipo de valor de servidor que deseamos configurar. Por ejemplo, para configurar una marca de tiempo cuando se crea un usuario podemos hacer lo siguiente:

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

"timestamp" es el único valor de servidor admitido y es el tiempo en milisegundos desde la época UNIX.

Mejora el rendimiento de escritura

Si escribimos cantidades grandes de datos en la base de datos, podemos usar el parámetro print=silent para mejorar nuestro rendimiento de escritura y reducir el uso del ancho de banda. En el comportamiento de escritura normal, el servidor responde con los datos JSON escritos. Cuando se especifica print=silent, el servidor cierra la conexión de inmediato una vez que se reciben los datos, lo que reduce el uso del ancho de banda.

En casos en los que se harán muchas solicitudes a la base de datos, podemos volver a usar la conexión HTTPS. Para esto, se debe enviar una solicitud Keep-Alive en el encabezado HTTP.

Condiciones de error

La API de REST mostrará códigos de error en las siguientes circunstancias:

Códigos de estado de HTTP
400 Solicitud incorrecta

Una de las siguientes condiciones de error:

  • No se pueden analizar los datos de PUT o POST.
  • Faltan datos de PUT o POST.
  • Los intentos de solicitud de datos PUT o POST son demasiado largos.
  • La llamada a la API de REST contiene nombres secundarios no válidos como parte de la ruta de acceso.
  • La ruta de acceso de la llamada de la API de REST es demasiado larga.
  • La solicitud contiene un valor de servidor no reconocido.
  • El índice de la consulta no está definido en Firebase Realtime Database Security Rules.
  • La solicitud no admite uno de los parámetros de consulta que se especificó.
  • La solicitud mezcla parámetros de consulta con una solicitud GET superficial.
401 Sin autorización

Una de las siguientes condiciones de error:

  • El token de autenticación caducó.
  • El token de autenticación que se usó en la solicitud no es válido.
  • Error en autenticación con access_token.
  • La solicitud infringe Firebase Realtime Database Security Rules.
404 No se encuentra No se encontró la base de datos Firebase especificada.
500 Error interno del servidor El servidor mostró un error. Revisa el mensaje de error para ver más detalles.
503 Servicio no disponible La Firebase Realtime Database especificada no está disponible temporalmente, lo que significa que no se intentó realizar la solicitud.

Protege los datos

Firebase tiene un lenguaje de seguridad que nos permite definir los usuarios que tienen acceso de lectura y escritura a distintos nodos de nuestros datos. Puedes obtener más información sobre este tema en Realtime Database Security Rules.

Ahora que analizamos cómo guardar datos, puedes aprender a recuperarlos de la base de datos de Firebase a través de la API de REST en la siguiente sección.