1. Antes de comenzar
Una extensión de Firebase realiza una tarea o un conjunto de tareas específicos en respuesta a solicitudes HTTP o a eventos de activación de otros productos de Firebase y Google, como Firebase Cloud Messaging, Cloud Firestore o Pub/Sub.
Qué compilarás
En este codelab, compilarás una extensión de Firebase para el geohashing. Una vez implementada, la extensión convierte las coordenadas X e Y en códigos geográficos en respuesta a eventos de Firestore o a través de invocaciones de funciones llamables. Esto se puede usar como alternativa a implementar la biblioteca de GeoFire en todas tus plataformas de destino para almacenar datos, lo que te ahorrará tiempo.
Qué aprenderás
- Cómo tomar el código existente de Cloud Functions y convertirlo en una extensión de Firebase distribuible
- Cómo configurar un archivo
extension.yaml
- Cómo almacenar cadenas sensibles (claves de API) en una extensión
- Cómo permitir que los desarrolladores de la extensión la configuren según sus necesidades
- Cómo probar e implementar la extensión
Requisitos
- Firebase CLI (instala y accede)
- Una Cuenta de Google, como una cuenta de Gmail
- Node.js y
npm
- Tu entorno de desarrollo favorito
2. Prepárate
Obtén el código
Todo lo que necesitas para esta extensión se encuentra en un repositorio de GitHub. Para comenzar, obtén el código y ábrelo en tu entorno de desarrollo favorito.
- Descomprime el archivo ZIP que se descargó.
- Para instalar las dependencias requeridas, abre la terminal en el directorio
functions
y ejecuta el comandonpm install
.
Configura Firebase
En este codelab, se recomienda el uso de los emuladores de Firebase. Si quieres probar el desarrollo de extensiones con un proyecto real de Firebase, consulta cómo crear un proyecto de Firebase. En este codelab, se usa Cloud Functions, por lo que, si usas un proyecto de Firebase real en lugar de los emuladores, debes actualizar al plan de precios Blaze.
¿Quieres adelantarte?
Puedes descargar una versión completa del codelab. Si te bloqueas en algún momento o quieres ver cómo se ve una extensión completa, consulta la rama codelab-end
del repositorio de GitHub o descarga el archivo ZIP completo.
3. Revisa el código
- Abre el archivo
index.ts
del archivo ZIP. Ten en cuenta que contiene dos declaraciones de Cloud Functions.
¿Qué hacen estas funciones?
Estas funciones de demostración se usan para el geohashing. Toman un par de coordenadas y las convierten en un formato optimizado para las búsquedas geográficas en Firestore. Las funciones simulan el uso de una llamada a la API para que puedas obtener más información sobre el manejo de tipos de datos sensibles en extensiones. Para obtener más información, consulta la documentación sobre cómo ejecutar búsquedas geográficas en los datos de Firestore.
Constantes de funciones
Las constantes se declaran al principio, en la parte superior del archivo index.ts
. Algunas de estas constantes se mencionan en los activadores definidos de la extensión.
index.ts
import {firestore} from "firebase-functions";
import {initializeApp} from "firebase-admin/app";
import {GeoHashService, ResultStatusCode} from "./fake-geohash-service";
import {onCall} from "firebase-functions/v1/https";
import {fieldValueExists} from "./utils";
const documentPath = "users/{uid}";
const xField = "xv";
const yField = "yv";
const apiKey = "1234567890";
const outputField = "hash";
initializeApp();
const service = new GeoHashService(apiKey);
Firestore Trigger
La primera función del archivo index.ts
se ve de la siguiente manera:
index.ts
export const locationUpdate = firestore.document(documentPath)
.onWrite((change) => {
// item deleted
if (change.after == null) {
return 0;
}
// double check that both values exist for computation
if (
!fieldValueExists(change.after.data(), xField) ||
!fieldValueExists(change.after.data(), yField)
) {
return 0;
}
const x: number = change.after.data()![xField];
const y: number = change.after.data()![yField];
const hash = service.convertToHash(x, y);
// This is to check whether the hash value has changed. If
// it hasn't, you don't want to write to the document again as it
// would create a recursive write loop.
if (fieldValueExists(change.after.data(), outputField)
&& change.after.data()![outputField] == hash) {
return 0;
}
return change.after.ref
.update(
{
[outputField]: hash.hash,
}
);
});
Esta función es un activador de Firestore. Cuando se produce un evento de escritura en la base de datos, la función reacciona a ese evento buscando un campo xv
y un campo yv
, y, si existen ambos campos, calcula el código geográfico y escribe el resultado en la ubicación de salida del documento especificada. El documento de entrada se define con la constante users/{uid}
, lo que significa que la función lee cada documento escrito en la colección users/
y, luego, procesa un código geográfico para esos documentos. Luego, genera el hash en un campo de hash del mismo documento.
Funciones que admiten llamadas
La siguiente función en el archivo index.ts
se ve de la siguiente manera:
index.ts
export const callableHash = onCall((data, context) => {
if (context.auth == undefined) {
return {error: "Only authorized users are allowed to call this endpoint"};
}
const x = data[xField];
const y = data[yField];
if (x == undefined || y == undefined) {
return {error: "Either x or y parameter was not declared"};
}
const result = service.convertToHash(x, y);
if (result.status != ResultStatusCode.ok) {
return {error: `Something went wrong ${result.message}`};
}
return {result: result.hash};
});
Observa la función onCall
. Indica que esta función es una función que admite llamadas, a la que se puede llamar desde el código de tu aplicación cliente. Esta función llamable toma parámetros x
y y
, y devuelve un código geográfico. Si bien esta función no se llamará directamente en este codelab, se incluye aquí como ejemplo de algo que se puede configurar en la extensión de Firebase.
4. Configura un archivo extension.yaml
Ahora que sabes qué hace el código de Cloud Functions en tu extensión, puedes empaquetarlo para distribuirlo. Cada extensión de Firebase incluye un archivo extension.yaml
que describe lo que hace la extensión y cómo se comporta.
Un archivo extension.yaml
requiere algunos metadatos iniciales sobre tu extensión. Cada uno de los siguientes pasos te ayuda a comprender qué significan todos los campos y por qué los necesitas.
- Crea un archivo
extension.yaml
en el directorio raíz del proyecto que descargaste antes. Comienza por agregar lo siguiente:
name: geohash-ext
version: 0.0.1
specVersion: v1beta # Firebase Extensions specification version (do not edit)
El nombre de la extensión se usa como base del ID de instancia de la extensión (los usuarios pueden instalar varias instancias de una extensión, cada una con su propio ID). Luego, Firebase genera el nombre de las cuentas de servicio y los recursos específicos de la extensión con ese ID de instancia. El número de versión indica la versión de tu extensión. Debe seguir el versionamiento semántico y debes actualizarlo cada vez que realices cambios en la funcionalidad de la extensión. La versión de la especificación de la extensión se usa para determinar qué especificación de extensiones de Firebase seguir. En este caso, se usa v1beta
.
- Agrega algunos detalles fáciles de usar al archivo YAML:
...
displayName: Latitude and longitude to GeoHash converter
description: A converter for changing your Latitude and longitude coordinates to geohashes.
El nombre visible es una representación descriptiva del nombre de tu extensión cuando los desarrolladores interactúan con ella. La descripción proporciona una breve descripción general de lo que hace la extensión. Cuando la extensión se implementa en extensions.dev, se ve de la siguiente manera:
- Especifica la licencia del código de tu extensión.
...
license: Apache-2.0 # The license you want for the extension
- Indica quién escribió la extensión y si se requiere facturación para instalarla:
...
author:
authorName: AUTHOR_NAME
url: https://github.com/Firebase
billingRequired: true
La sección author
se usa para que los usuarios sepan a quién comunicarse en caso de que tengan problemas con la extensión o quieran obtener más información sobre ella. billingRequired
es un parámetro obligatorio y debe establecerse en true
, ya que todas las extensiones dependen de Cloud Functions, que requiere el plan Blaze.
Esto abarca la cantidad mínima de campos requeridos en el archivo extension.yaml
para identificar esta extensión. Para obtener más detalles sobre otra información de identificación que puedes especificar en una extensión, consulta la documentación.
5. Convierte el código de Cloud Functions en un recurso de Extensiones
Un recurso de extensión es un elemento que Firebase crea en el proyecto durante la instalación de una extensión. Luego, la extensión es propietaria de esos recursos y tiene una cuenta de servicio específica que opera en ellos. En este proyecto, esos recursos son Cloud Functions, que deben definirse en el archivo extension.yaml
porque la extensión no creará recursos automáticamente a partir del código de la carpeta de funciones. Si tus Cloud Functions no se declaran explícitamente como un recurso, no se podrán implementar cuando se implemente la extensión.
Ubicación de implementación definida por el usuario
- Permite que el usuario especifique la ubicación en la que desea implementar esta extensión y decida si sería mejor alojarla más cerca de sus usuarios finales o de su base de datos. En el archivo
extension.yaml
, incluye la opción para elegir una ubicación.
extension.yaml
Ahora puedes escribir la configuración del recurso de la función.
- En el archivo
extension.yaml
, crea un objeto de recurso para la funciónlocationUpdate
. Agrega lo siguiente al archivoextension.yaml
:
resources:
- name: locationUpdate
type: firebaseextensions.v1beta.function
properties:
eventTrigger:
eventType: providers/cloud.firestore/eventTypes/document.write
resource: projects/${PROJECT_ID}/databases/(default)/documents/users/{uid}
Defines name
como el nombre de la función definida en el archivo index.ts
del proyecto. Especifica el type
de la función que se implementa, que siempre debe ser firebaseextensions.v1beta.function
por el momento. Luego, defines el properties
de esta función. La primera propiedad que defines es el eventTrigger
que está asociado a esta función. Para reflejar lo que admite actualmente la extensión, usa el eventType
de providers/cloud.firestore/eventTypes/document.write
, que se encuentra en la documentación de Escribe Cloud Functions para tu extensión. Defines resource
como la ubicación de los documentos. Dado que tu objetivo actual es reflejar lo que existe en el código, la ruta del documento escucha users/{uid}
, con la ubicación predeterminada de la base de datos que la precede.
- La extensión necesita permisos de lectura y escritura para la base de datos de Firestore. Al final del archivo
extension.yaml
, especifica los roles de IAM a los que debe tener acceso la extensión para trabajar con la base de datos en el proyecto de Firebase del desarrollador.
roles:
- role: datastore.user
reason: Allows the extension to read / write to your Firestore instance.
El rol datastore.user
proviene de la lista de roles de IAM admitidos para extensiones. Dado que la extensión leerá y escribirá, el rol datastore.user
es adecuado aquí.
- También se debe agregar la función a la que se puede llamar. En el archivo
extension.yaml
, crea un recurso nuevo en la propiedad resources. Estas propiedades son específicas de una función que se puede llamar:
- name: callableHash
type: firebaseextensions.v1beta.function
properties:
httpsTrigger: {}
Aunque el recurso anterior usaba un eventTrigger
, aquí usas un httpsTrigger
, que abarca tanto las funciones que admiten llamadas como las funciones HTTPS.
Verificación de código
Fue mucha configuración para que tu extension.yaml
coincida con todo lo que hace el código en tu archivo index.ts
. Así debería verse el archivo extension.yaml
completo en este momento:
extension.yaml
name: geohash-ext
version: 0.0.1
specVersion: v1beta # Firebase Extensions specification version (do not edit)
displayName: Latitude and Longitude to GeoHash converter
description: A converter for changing your Latitude and Longitude coordinates to geohashes.
license: Apache-2.0 # The license you want for the extension
author:
authorName: Sparky
url: https://github.com/Firebase
billingRequired: true
resources:
- name: locationUpdate
type: firebaseextensions.v1beta.function
properties:
eventTrigger:
eventType: providers/cloud.firestore/eventTypes/document.write
resource: projects/${PROJECT_ID}/databases/(default)/documents/users/{uid}
- name: callableHash
type: firebaseextensions.v1beta.function
properties:
httpsTrigger: {}
roles:
- role: datastore.user
reason: Allows the extension to read / write to your Firestore instance.
Verificación de estado
En este punto, ya tienes configuradas las partes funcionales iniciales de la extensión, por lo que puedes probarla con los emuladores de Firebase.
- Si aún no lo hiciste, llama a
npm run build
en la carpeta de funciones del proyecto de extensiones descargado. - Crea un directorio nuevo en tu sistema host y conéctalo a tu proyecto de Firebase con
firebase init
.
cd .. mkdir sample-proj cd sample-proj firebase init --project=projectID-or-alias
This command creates a `firebase.json` file in the directory. In the following steps, you push the configuration specified in this file to Firebase.
- Desde el mismo directorio, ejecuta
firebase ext:install
. Reemplaza/path/to/extension
por la ruta de acceso absoluta al directorio que contiene tu archivoextension.yaml
.
firebase ext:install /path/to/extension
This command does two things:
- Se te pedirá que especifiques la configuración de la instancia de extensión y se creará un archivo
*.env
que contiene la información de configuración de la instancia. - Agrega la instancia de extensión a la sección
extensions
de tufirebase.json
. Esto funciona como un mapa del ID de instancia a la versión de la extensión. - Como implementarás el proyecto de forma local, puedes especificar que deseas usar un archivo local en lugar de Google Cloud Secret Manager.
- Inicia los emuladores de Firebase con la nueva configuración:
firebase emulators:start
- Después de ejecutar
emulators:start
, navega a la pestaña Firestore en la vista web de los emuladores. - Agrega un documento a la colección
users
con un campo de númeroxv
y un campo de númeroyv
.
- Si instalaste la extensión correctamente, esta creará un campo nuevo llamado
hash
en el documento.
Realiza una limpieza para evitar conflictos
- Cuando termines de probarla, desinstala la extensión, ya que actualizarás el código de la extensión y no querrás que haya conflictos con la extensión actual más adelante.
Las extensiones permiten instalar varias versiones de la misma extensión a la vez, por lo que, al desinstalarlas, te aseguras de que no haya conflictos con una extensión instalada anteriormente.
firebase ext:uninstall geohash-ext
La solución actual funciona, pero, como se mencionó al principio del proyecto, hay una clave de API codificada para simular la comunicación con un servicio. ¿Cómo puedes usar la clave de API del usuario final en lugar de la que se proporcionó originalmente? Sigue leyendo para descubrirlo.
6. Haz que la extensión sea configurable por el usuario
En este punto del codelab, tienes una extensión configurada para usarla con la configuración basada en opiniones de las funciones que ya escribiste, pero ¿qué sucede si el usuario quiere usar la latitud y la longitud en lugar de y y x para los campos que indican la ubicación en un plano cartesiano? Además, ¿cómo puedes hacer para que el usuario final proporcione su propia clave de API en lugar de permitirle consumir la clave de API proporcionada? Podrías superar rápidamente la cuota de esa API. En este caso, configurarás y usarás parámetros.
Define parámetros básicos en el archivo extension.yaml
Comienza por convertir los elementos para los que los desarrolladores podrían tener una configuración personalizada. El primero serían los parámetros XFIELD
y YFIELD
.
- En el archivo
extension.yaml
, agrega el siguiente código, que usa los parámetros de campoXFIELD
yYFIELD
. Estos parámetros se encuentran dentro de la propiedadparams
de YAML definida anteriormente:
extension.yaml
params:
- param: XFIELD
label: The X Field Name
description: >-
The X Field is also known as the **longitude** value. What does
your Firestore instance refer to as the X value or the longitude
value. If no value is specified, the extension searches for
field 'xv'.
type: string
validationRegex: ^\D([0-9a-zA-Z_.]{0,375})$
validationErrorMessage: >-
The field can only contain uppercase or lowercase letter, numbers,
_, and . characters and must be less than 1500 bytes long. The field
must also not start with a number.
default: xv
required: false
immutable: false
example: xv
- param: YFIELD
label: The Y Field Name
description: >-
The Y Field is also known as the **latitude** value. What does
your Firestore instance refer to as the Y value or the latitude
value. If no value is specified, the extension searches for
field 'yv'.
type: string
validationRegex: ^\D([0-9a-zA-Z_.]{0,375})$
validationErrorMessage: >-
The field can only contain uppercase or lowercase letter, numbers,
_, and . characters and must be less than 1500 bytes long. The field
must also not start with a number.
default: yv
required: false
immutable: false
example: yv
- param nombra el parámetro de una manera que es visible para ti, el productor de la extensión. Usa este valor más adelante cuando especifiques los valores de los parámetros.
- label es un identificador legible para el desarrollador que le permite saber qué hace el parámetro.
- description proporciona una descripción detallada del valor. Como admite Markdown, puede vincularse a documentación adicional o destacar palabras que podrían ser importantes para el desarrollador.
- type define el mecanismo de entrada para establecer el valor del parámetro. Existen muchos tipos, incluidos
string
,select
,multiSelect
,selectResource
ysecret
. Para obtener más información sobre cada una de estas opciones, consulta la documentación. - validationRegex limita la entrada del desarrollador a un determinado valor de regex (en el ejemplo, se basa en los lineamientos simples para el nombre del campo que se encuentran aquí). Si eso falla…
- validationErrorMessage alerta al desarrollador sobre el valor de falla.
- default es el valor que tendría si el desarrollador no ingresara ningún texto.
- required significa que el desarrollador no debe ingresar ningún texto.
- immutable permite que el desarrollador actualice esta extensión y cambie este valor. En este caso, el desarrollador debería poder cambiar los nombres de los campos a medida que cambien sus requisitos.
- example proporciona una idea de cómo podría verse una entrada válida.
¡Eso fue mucho que comprender!
- Antes de agregar un parámetro especial, debes agregar tres parámetros más al archivo
extension.yaml
.
- param: INPUTPATH
label: The input document to listen to for changes
description: >-
This is the document where you write an x and y value to. Once
that document has received a value, it notifies the extension to
calculate a geohash and store that in an output document in a certain
field. This accepts function [wildcard parameters](https://firebase.google.com/docs/functions/firestore-events#wildcards-parameters)
type: string
validationRegex: ^[^/]+(/[^/]*/[^/]*)*/[^/]+$
validationErrorMessage: >-
This must point to a document path, not a collection path from the root
of the database. It must also not start or end with a '/' character.
required: true
immutable: false
example: users/{uid}
- param: OUTPUTFIELD
label: Geohash field
description: >-
This specifies the field in the output document to store the geohash in.
type: string
validationRegex: ^\D([0-9a-zA-Z_.]{0,375})$
validationErrorMessage: >-
The field can only contain uppercase or lowercase letter, numbers,
_, and . characters and must be less than 1500 bytes long. The field
must also not start with a number.
required: false
default: hash
immutable: false
example: hash
Define parámetros sensibles
Ahora, debes administrar la clave de API que especifica el usuario. Esta es una cadena sensible que no se debe almacenar como texto sin formato en la función. En su lugar, almacena este valor en Cloud Secret Manager. Esta es una ubicación especial en la nube que almacena secretos encriptados y evita que se filtren accidentalmente. Esto requiere que el desarrollador pague por el uso de este servicio, pero agrega una capa adicional de seguridad a sus claves de API y, potencialmente, limita la actividad fraudulenta. La documentación del usuario alerta al desarrollador de que se trata de un servicio pagado, por lo que no habrá sorpresas en la facturación. En general, el uso es similar al de los otros recursos de cadenas mencionados anteriormente. La única diferencia es el tipo, que se llama secret
.
- En el archivo
extension.yaml
, agrega el siguiente código:
extension.yaml
- param: APIKEY
label: GeohashService API Key
description: >-
Your geohash service API Key. Since this is a demo, and not a real
service, you can use : 1234567890.
type: secret
required: true
immutable: false
Actualiza los atributos para usar parámetros de resource
Como se mencionó anteriormente, el recurso (no la función) define cómo se observa el recurso, por lo que se debe actualizar el recurso locationUpdate
para usar el nuevo parámetro.
- En el archivo
extension.yaml
, agrega el siguiente código:
extension.yaml
## Change from this
- name: locationUpdate
type: firebaseextensions.v1beta.function
properties:
eventTrigger:
eventType: providers/cloud.firestore/eventTypes/document.write
resource: projects/${PROJECT_ID}/databases/(default)/documents/users/{uid}]
## To this
- name: locationUpdate
type: firebaseextensions.v1beta.function
properties:
eventTrigger:
eventType: providers/cloud.firestore/eventTypes/document.write
resource: projects/${PROJECT_ID}/databases/(default)/documents/${INPUTPATH}
Verifica el archivo extension.yaml
- Revisa el archivo
extension.yaml
. Debería verse algo similar a esto:
extension.yaml
name: geohash-ext
version: 0.0.1
specVersion: v1beta # Firebase Extensions specification version (do not edit)
displayName: Latitude and Longitude to GeoHash converter
description: A converter for changing your Latitude and Longitude coordinates to geohashes.
license: Apache-2.0 # The license you want to use for the extension
author:
authorName: Sparky
url: https://github.com/Firebase
billingRequired: true
params:
- param: XFIELD
label: The X Field Name
description: >-
The X Field is also known as the **longitude** value. What does
your Firestore instance refer to as the X value or the longitude
value. If you don't provide a value for this field, the extension will use 'xv' as the default value.
type: string
validationRegex: ^\D([0-9a-zA-Z_.]{0,375})$
validationErrorMessage: >-
The field can only contain uppercase or lowercase letter, numbers,
_, and . characters and must be less than 1500 bytes long. The field
must also not start with a number.
default: xv
required: false
immutable: false
example: xv
- param: YFIELD
label: The Y Field Name
description: >-
The Y Field is also known as the **latitude** value. What does
your Firestore instance refer to as the Y value or the latitude
Value. If you don't provide a value for this field, the extension will use 'yv' as the default value.
type: string
validationRegex: ^\D([0-9a-zA-Z_.]{0,375})$
validationErrorMessage: >-
The field can only contain uppercase or lowercase letter, numbers,
_, and . characters and must be less than 1500 bytes long. The field
must also not start with a number.
default: yv
required: false
immutable: false
example: yv
- param: INPUTPATH
label: The input document to listen to for changes
description: >-
This is the document where you write an x and y value to. Once
that document has been modified, it notifies the extension to
compute a geohash and store that in an output document in a certain
field. This accepts function [wildcard parameters](https://firebase.google.com/docs/functions/firestore-events#wildcards-parameters)
type: string
validationRegex: ^[^/]+(/[^/]*/[^/]*)*/[^/]+$
validationErrorMessage: >-
This must point to a document path, not a collection path from the root
of the database. It must also not start or end with a '/' character.
required: true
immutable: false
example: users/{uid}
- param: OUTPUTFIELD
label: Geohash field
description: >-
This specifies the field in the output document to store the geohash in.
type: string
validationRegex: ^\D([0-9a-zA-Z_.]{0,375})$
validationErrorMessage: >-
The field can only contain uppercase or lowercase letter, numbers,
_, and . characters and must be less than 1500 bytes long. The field
must also not start with a number.
required: false
default: hash
immutable: false
example: hash
- param: APIKEY
label: GeohashService API Key
description: >-
Your geohash service API Key. Since this is a demo, and not a real
service, you can use : 1234567890.
type: secret
required: true
immutable: false
resources:
- name: locationUpdate
type: firebaseextensions.v1beta.function
properties:
eventTrigger:
eventType: providers/cloud.firestore/eventTypes/document.write
resource: projects/${PROJECT_ID}/databases/(default)/documents/${INPUTPATH}
- name: callableHash
type: firebaseextensions.v1beta.function
properties:
httpsTrigger: {}
roles:
- role: datastore.user
reason: Allows the extension to read / write to your Firestore instance.
Cómo acceder a los parámetros en el código
Ahora que todos los parámetros están configurados en el archivo extension.yaml
, agrégalos al archivo index.ts
.
- En el archivo
index.ts
, reemplaza los valores predeterminados porprocess.env.PARAMETER_NAME
, que recupera los valores de parámetros adecuados y los completa en el código de la función implementado en el proyecto de Firebase del desarrollador.
index.ts
// Replace this:
const documentPath = "users/{uid}";
const xField = "xv";
const yField = "yv";
const apiKey = "1234567890";
const outputField = "hash";
// with this:
const documentPath = process.env.INPUTPATH!; // this value is ignored since its read from the resource
const xField = process.env.XFIELD!;
const yField = process.env.YFIELD!;
const apiKey = process.env.APIKEY!;
const outputField = process.env.OUTPUTFIELD!;
Normalmente, querrás realizar verificaciones de nulos con los valores de las variables de entorno, pero, en este caso, confías en que los valores de los parámetros se copian correctamente. Ahora el código está configurado para funcionar con los parámetros de extensión.
7. Crear documentación para el usuario
Antes de probar el código en emuladores o en el mercado de extensiones de Firebase, se debe documentar la extensión para que los desarrolladores sepan qué obtendrán cuando la usen.
- Comienza por crear el archivo
PREINSTALL.md
, que se usa para describir la funcionalidad, los requisitos previos para la instalación y las posibles implicaciones de facturación.
PREINSTALL.md
Use this extension to automatically convert documents with a latitude and
longitude to a geohash in your database. Additionally, this extension includes a callable function that allows users to make one-time calls
to convert an x,y coordinate into a geohash.
Geohashing is supported for latitudes between 90 and -90 and longitudes
between 180 and -180.
#### Third Party API Key
This extension uses a fictitious third-party API for calculating the
geohash. You need to supply your own API keys. (Since it's fictitious,
you can use 1234567890 as an API key).
#### Additional setup
Before installing this extension, make sure that you've [set up a Cloud
Firestore database](https://firebase.google.com/docs/firestore/quickstart) in your Firebase project.
After installing this extension, you'll need to:
- Update your client code to point to the callable geohash function if you
want to perform arbitrary geohashes.
Detailed information for these post-installation tasks are provided after
you install this extension.
#### Billing
To install an extension, your project must be on the [Blaze (pay as you
go) plan](https://firebase.google.com/pricing)
- This extension uses other Firebase and Google Cloud Platform services,
which have associated charges if you exceed the service's no-cost tier:
- Cloud Firestore
- Cloud Functions (Node.js 16+ runtime. [See
FAQs](https://firebase.google.com/support/faq#extensions-pricing))
- [Cloud Secret Manager](https://cloud.google.com/secret-manager/pricing)
- Para ahorrar tiempo al escribir el
README.md
para este proyecto, usa el método de conveniencia:
firebase ext:info . --markdown > README.md
Esto combina el contenido de tu archivo PREINSTALL.md
y los detalles adicionales sobre tu extensión de tu archivo extension.yaml
.
Por último, informa al desarrollador de la extensión sobre algunos detalles adicionales relacionados con la extensión que se acaba de instalar. Es posible que el desarrollador reciba algunas instrucciones e información adicionales después de completar la instalación, y que deba realizar algunas tareas detalladas posteriores a la instalación, como configurar el código del cliente.
- Crea un archivo
POSTINSTALL.md
y, luego, incluye la siguiente información posterior a la instalación:
POSTINSTALL.md
Congratulations on installing the geohash extension!
#### Function information
* **Firestore Trigger** - ${function:locationUpdate.name} was installed
and is invoked when both an x field (${param:XFIELD}) and y field
(${param:YFIELD}) contain a value.
* **Callable Trigger** - ${function:callableHash.name} was installed and
can be invoked by writing the following client code:
```javascript
import { getFunctions, httpsCallable } from "firebase/functions";
const functions = getFunctions();
const geoHash = httpsCallable(functions, '${function:callableHash.name}');
geoHash({ ${param:XFIELD}: -122.0840, ${param:YFIELD}: 37.4221 })
.then((result) => {
// Read result of the Cloud Function.
/** @type {any} */
const data = result.data;
const error = data.error;
if (error != null) {
console.error(`callable error : ${error}`);
}
const result = data.result;
console.log(result);
});
Supervisión
Como práctica recomendada, puedes supervisar la actividad de la extensión que instalaste, incluidas las verificaciones de estado, uso y registros.
The output rendering looks something like this when it's deployed:
<img src="img/82b54a5c6ca34b3c.png" alt="A preview of the latitude and longitude geohash converter extension in the firebase console" width="957.00" />
## Test the extension with the full configuration
Duration: 03:00
It's time to make sure that the user-configurable extension is working the way it is intended.
* Change into the functions folder and ensure that the latest compiled version of the extensions exists. In the extensions project functions directory, call:
```console
npm run build
Esto vuelve a compilar las funciones para que el código fuente más reciente esté listo para la implementación junto con la extensión cuando se implemente en un emulador o directamente en Firebase.
A continuación, crea un directorio nuevo para probar la extensión. Dado que la extensión se desarrolló a partir de funciones existentes, no realices pruebas desde la carpeta en la que se configuró la extensión, ya que eso también intentará implementar las funciones y las reglas de Firebase junto con ella.
Instala y prueba con los emuladores de Firebase
- Crea un directorio nuevo en tu sistema host y conéctalo a tu proyecto de Firebase con
firebase init
.
mkdir sample-proj cd sample-proj firebase init --project=projectID-or-alias
- Desde ese directorio, ejecuta
firebase ext:install
para instalar la extensión. Reemplaza/path/to/extension
por la ruta de acceso absoluta al directorio que contiene tu archivoextension.yaml
. Esto inicia el proceso de instalación de la extensión y crea un archivo.env
que contiene tus configuraciones antes de enviar la configuración a Firebase o a los emuladores.
firebase ext:install /path/to/extension
- Como implementarás el proyecto de forma local, especifica que deseas usar un archivo local en lugar de Google Cloud Secret Manager.
- Inicia el conjunto de emuladores locales:
firebase emulators:start
Instala y prueba la extensión con un proyecto real de Firebase
Puedes instalar tu extensión en un proyecto real de Firebase. Se recomienda usar un proyecto de prueba. Usa este flujo de trabajo de prueba si quieres probar el flujo de extremo a extremo de tu extensión o si el activador de la extensión aún no es compatible con Firebase Emulator Suite (consulta la opción del emulador de extensiones). Actualmente, los emuladores admiten funciones que se activan por solicitud HTTP y por eventos en segundo plano para Cloud Firestore, Realtime Database y Pub/Sub.
- Crea un directorio nuevo en tu sistema host y conéctalo a tu proyecto de Firebase con
firebase init
.
cd .. mkdir sample-proj cd sample-proj firebase init --project=projectID-or-alias
- Luego, desde ese directorio, ejecuta
firebase ext:install
para instalar la extensión. Reemplaza/path/to/extension
por la ruta de acceso absoluta al directorio que contiene tu archivoextension.yaml
. Esto inicia el proceso de instalación de la extensión y crea un archivo.env
que contiene tus configuraciones antes de enviar la configuración a Firebase o a los emuladores.
firebase ext:install /path/to/extension
- Como deseas realizar la implementación directamente en Firebase y usar Google Cloud Secret Manager, debes activar la API de Secret Manager antes de instalar la extensión.
- Implementa en tu proyecto de Firebase.
firebase deploy
Prueba la extensión
- Después de ejecutar
firebase deploy
ofirebase emulators:start
, navega a la pestaña Firestore de Firebase console o la vista web de los emuladores, según corresponda. - Agrega un documento a la colección especificada por los campos
x
yy
. En este caso, los documentos actualizados se encuentran enu/{uid}
con un campox
dexv
y un campoy
deyv
.
- Si instalaste la extensión correctamente, esta creará un campo nuevo llamado
hash
en el documento después de que guardes los dos campos.
8. ¡Felicitaciones!
Convertiste correctamente tu primera Cloud Function en una extensión de Firebase.
Agregaste un archivo extension.yaml
y lo configuraste para que los desarrolladores puedan seleccionar cómo quieren que se implemente tu extensión. Luego, creaste documentación para el usuario que brinda orientación sobre lo que los desarrolladores de la extensión deben hacer antes de configurarla y los pasos que podrían tener que seguir después de instalarla correctamente.
Ahora conoces los pasos clave necesarios para convertir una Firebase Function en una extensión de Firebase distribuible.