Estos días he estado probando la API de Google Cloud Storage para poder acceder a ficheros, o como ellos lo denominan objetos, que tengo almacenados desde una aplicación web. En este tutorial hablaré de los pasos que he seguido para poder hacerlo.
Índice de contenidos
- ¿Que es Google Cloud Storage?
- Configuración inicial
- Interacción con el bucket
- Configuración del token de acceso OAuth 2.0
- Descarga de objetos
- Subida de objetos
- Conclusiones
¿Que es Google Cloud Storage?
Google Cloud Storage es un servicio para almacenar tus objetos en Google Cloud. Un objeto es un dato individual que almacenas en Cloud Storage, está compuesto por dos componentes:
- Los datos de objeto, que suelen ser los archivos en sí.
- Los metadatos, que son una recopilación de pares nombre-valor en los que se describen varias cualidades del objeto.
Los objetos se almacenan en contenedores llamados buckets. Todos los buckets están asociados con un proyecto que, a su vez, se puede agrupar en una organización.
Configuración inicial
Para poder interactuar con un bucket en Google Cloud, necesitaremos realizar una serie de pasos previos, que serán los siguientes:
- Necesitaremos tener una cuenta de Google.
- Una vez creada, entraremos en la plataforma de Google Cloud.
- Dentro de la misma, crearemos un tipo de cuenta gratuito para poder hacer pruebas con la API de Google.
- Una vez creada, podremos interactuar con los servicios que nos ofrece Google, haremos click en consola.
- Para poder crear nuestros buckets de archivos necesitaremos tener un proyecto, esto lo haremos haciendo click en “selecciona un proyecto” y posteriormente en “proyecto nuevo”, rellenaremos una serie de datos y ya tendremos creado nuestro primer proyecto.
- Ahora crearemos nuestro bucket, que es el lugar donde vamos a almacenar nuestros objetos. Para hacer esto, tendremos que rellenar un formulario con una serie de datos, el primero de estos será el nombre. Es importante que recordemos que el nombre del bucket se encuentra en un espacio de nombres que comparten todos los usuarios de Cloud Storage, por lo que el nombre que le pongamos a nuestro bucket tiene que ser único, estas son las recomendaciones que da Google para darle un nombre a nuestro bucket.
- Tras indicar el nombre que le vamos a dar a nuestro bucket, vamos a seleccionar en donde se van a alojar nuestros datos, lo recomendado es seleccionar la opción de multi-región.
- El resto de datos se rellenarán solos (posteriormente podremos modificarlos, pero para este tutorial no va a ser necesario hacerlo).
Una vez hayamos completado todos los pasos anteriores, tendremos listo nuestro primer bucket para interactuar con él.
Interacción con el Bucket
Ahora que hemos creado el bucket tenemos varias opciones para interactuar con el mismo, contamos con tres maneras de hacerlo:
- Desde la plataforma de Google Cloud Storage.
- Por medio de las librerías de cliente de Google Cloud Storage.
- Realizando llamadas http por medio de la API Json de Cloud Storage, que es de la manera en la que lo vamos a hacer en este tutorial.
En la documentación de Google Cloud Storage, tenemos las llamadas que podemos realizar para interactuar con el bucket, podemos comenzar probando con una llamada para obtener información acerca del bucket en sí, según la documentación, la llamada http que deberíamos hacer sería la siguiente:
GET https://storage.googleapis.com/storage/v1/b/BUCKET_NAME
Previamente he creado una aplicación básica en React. En esta, he creado un servicio para hacer llamadas http con la configuración indicada en la imagen para interactuar con la API de Google. Para la gestión de llamadas http he utilizado la librería axios.
Dentro de la configuración del Cloud Storage, se nos indica que para acceder a nuestro bucket, debemos añadir el siguiente header en nuestra llamada http.
x-goog-project-id : ID
Estos datos se nos darían en la vista de configuración del bucket.
Ahora, si probamos a realizar la petición, en la pantalla de herramientas del desarrollador del navegador, en la pestaña de network veremos el siguiente error.
Básicamente, lo que nos quiere decir es que no nos hemos identificado a la hora de realizar la petición y no tenemos permisos para acceder al bucket. Por lo que tendremos que añadir un header que nos identifique en la petición al bucket.
Para ello, en nuestra configuración de la llamada http al Storage, vamos a tener que añadir un header Authorization (Bearer | GOOG1 | AWS).
Contamos con tres opciones con las que podemos poner este identificador de autorización, que serían las siguientes:
– Un token de acceso OAuth 2.0 válido
– Una clave de acceso
– Una firma
En este tutorial vamos a hacerlo siguiendo la primera opción, que explicaré en el siguiente punto.
Configuración del token de acceso OAuth 2.0
En esta sección explicaré dos maneras de obtener un token de acceso OAuth 2.0 válido para añadir a nuestro header Authorization.
En la documentación con respecto a la autentificación, nos dará diferentes opciones con las que obtener nuestro token de acceso.
OAuth 2.0 Playground
Esta es la manera más básica y sencilla de crear un token de acceso, que se usará en caso de que quieras jugar con las diferentes APIs de Google para hacer pruebas, esto se hará gracias al Playground de OAuth 2.0 de Google, que permite generar un token de acceso OAuth 2.0 de la API que quieras con los permisos que tu le indiques. Este mismo token generado lo puedes utilizar posteriormente en tu aplicación añadiéndolo a la cabecera de Authorization, o puedes utilizarlo para interactuar directamente con la API en el Playground. Este token de acceso tiene una caducidad puesta por defecto, que sería de unos 4000 segundos.
Ya que vamos a interactuar con la API de Cloud Storage, deberemos buscarla y seleccionar los permisos que queremos tener con nuestro token de acceso. En este caso, haré la selección de autorizar el control total.
Una vez creado el token, solo tendremos que añadirlo dentro de nuestra configuración de axios para realizar las llamadas http.
Si ahora intentamos hacer la petición de nuevo, pasará esto:
La petición se habrá dado exitosamente y habremos recibido los datos de nuestro bucket mediante una llamada a la API de Google Cloud Storage.
Cuenta de servicio
En el punto anterior se ha explicado como generar un token de acceso con el Playground de Google OAuth 2.0, con el que podemos realizar pruebas relativamente sencillas para probar nuestra API. En este punto vamos a utilizar algo que se podría aplicar a un caso de uso real, que sería haciendo uso de una cuenta de servicio.
¿Qué es una cuenta de servicio? Se trata de un tipo especial de cuenta que suele usar una aplicación o carga de trabajo de procesamiento, como una instancia de Compute Engine, en lugar de una persona. Se identifica por su dirección de correo electrónico, que es única a la cuenta.
Las aplicaciones utilizan este tipo de cuentas para realizar llamadas a la API autorizadas, que es justo lo que queremos hacer con esta aplicación.
Para hacer uso de esta cuenta de servicio, lo primero que tendremos que hacer será crearla, para esto dentro de nuestro proyecto, deberemos ir a IAM & administración y buscar la opción que dice Cuentas de servicio. Una vez dentro podremos crear la nuestra.
Deberemos rellenar una serie de datos, y uno de estos será darle a nuestra cuenta de servicio acceso al proyecto, indicando el rol o roles que queremos que tenga la misma, para este proyecto voy a indicar que el rol que quiero es el de Administrador de almacenamiento. Con el que voy a tener control total para gestionar nuestro bucket.
Una vez creada nuestra cuenta de servicio, tendremos que crear una clave, para que generar el token de acceso con el que consumir nuestra API.
Para crear esta clave, en la vista donde se mostrará nuestra cuenta de servicio recién creada, haremos click en el campo del email, esto nos llevará a la vista con la que podemos gestionar nuestra cuenta de servicio, iremos al apartado de claves y veremos un botón con la opción de agregar clave, al hacer click ahí veremos dos opciones, seleccionaremos la de crear clave nueva. Nos preguntará el tipo de clave que queremos crear, la recomendada es que sea de tipo JSON. Una vez creada, se nos descargará un archivo que servirá como copia única de nuestra clave privada, en caso de perderla, tocara crear una nueva.
Una vez que tenemos la clave privada, necesitaremos crear un token de acceso con el que consumir nuestra API, este access token lo vamos tener que solicitar al servidor de autorización de Google OAuth 2.0. Para ello, vamos a tener que crear un token JWT a partir del archivo JSON que hemos descargado al crear la clave de nuestra cuenta de tipo servicio.
El proceso que seguiremos será el siguiente:
Para crear nuestro token JWT yo he hecho uso de la librería jose (JSON Object Signing and Encryption). Se trata de una librería que nos ofrece una serie de utilidades para este tipo de procesos (crear token JWT, firmarlo,..etc).
En la documentación de Google se nos indica como generar el token JWT y de que está compuesto, por un lado tendríamos el encabezado del mismo, que estará compuesta de las siguientes partes
- alg – El Algoritmo que en este caso siempre será el mismo “RS256”
- typ – El tipo, que en nuestro caso es el “JWT”
- kid – El id de la clave privada que viene en el archivo JSON que se nos descargó anteriormente, el campo al que me refiero seria “private_key_id”
Ahora tendremos que conocer la siguiente parte necesaria para la creación del token JWT, que estará compuesta de las siguientes partes
- iss – La dirección de correo electrónico de la cuenta de servicio
- scope – Una lista delimitada por espacios de los permisos que solicita la aplicación
- aud – Un descriptor del destino previsto de la aserción. Cuando realizas una solicitud de token de acceso, este valor es siempre https://oauth2.googleapis.com/token
- exp – La hora de vencimiento de la aserción, especificada como segundos desde las 00:00:00 UTC, 1 de enero de 1970. Este valor tiene un máximo de 1 hora después del tiempo emitido
- iat – La hora a la que se emitió la aserción, especificada como segundos a partir de las 00:00:00 UTC, 1 de enero de 1970
Y por último, necesitaremos la firma, que constará de dos partes, el algoritmo que debe ser el mismo que tenemos en el encabezado “RS256”, que es el único compatible con el servidor de autorización de Google OAuth 2.0. Y por otro lado la clave privada, que sería el campo “private_key” en nuestro archivo JSON descargado anteriormente. En código quedaría algo como esto
Luego, solo tendremos que hacer una petición al servidor de autorización de Google OAuth 2.0
POST https://oauth2.googleapis.com/token
Con los siguientes query param:
- grant_type – Con la siguiente string, codificada en formato de URL según sea necesario: urn:ietf:params:oauth:grant-type:jwt-bearer
- assertion – El JWT, incluida la firma
Una vez hecho esto nos devolverá un access token, que es el que pondremos en el header Authorization junto al string “Bearer” en nuestra petición para interactuar con google cloud storage:
Con esto podremos realizar la petición de la misma manera que se mostró anteriormente.
Descarga de objetos
Ahora que hemos conseguido obtener datos del bucket exitosamente, vamos a darle algún tipo de utilidad al mismo, en mi caso, voy a querer crear una galería de imágenes, y estas van a estar alojadas en el Storage, por lo que primero vamos a ver como obtener los datos de todos los elementos que tenemos guardados en el Bucket. Gracias a la documentación de Google Cloud Storage, podremos ver todas las opciones que tenemos a la hora de interactuar con la API JSON. En este caso, queremos interactuar con el bucket y obtener todos los objetos del mismo, por lo que tendremos que hacer una petición GET al endpoint que nos devuelve datos del bucket.
Para este tutorial, he preparado una serie de imágenes que he subido al bucket en el storage, estas imágenes se pueden subir de dos maneras, o directamente al bucket a través de la interfaz de Google Cloud, que es de la manera en la que lo he hecho, o realizando una llamada POST a partir de la API JSON, que explicaré más adelante con un pequeño ejemplo.
Para subir los archivos únicamente debemos ir a la interfaz de nuestro bucket en la consola de Google y hacer click en el botón de subir archivos, seleccionarlos y ya lo tendríamos.
Una vez tengamos los objetos en nuestro bucket, únicamente tendremos que realizar la petición para obtener los elementos dentro de nuestro bucket, según la documentación, la petición sería la siguiente:
GET https://storage.googleapis.com/storage/v1/b/BUCKET_NAME/o
Si realizamos la siguiente petición en nuestra aplicación, obtendremos los siguientes datos:
Que vendría a ser una lista con la información de los objetos que tenemos almacenados en nuestro storage. De toda la información que nos ofrece, para descargar el objeto y mostrarlo en nuestra aplicación, nos interesara la propiedad mediaLink, que nos facilita la url necesaria para realizar la petición y descargar específicamente ese objeto, cabe destacar que para realizar esta petición hacen falta unos permisos específicos, que tendremos con el rol Administrador de almacenamiento. Existen otros roles que podemos ver en la documentación que nos permiten obtener los items del bucket, pero para este tutorial hemos escogido el que nos permite realizar más acciones.
La url sería la siguiente
GET https://storage.googleapis.com/download/storage/v1/b/BUCKET_NAME/o/OBJECT_NAME&alt=media"
Ahora gestionaremos nuestra aplicación para poder realizar la llamada, recibir el objeto y mostrarlo por pantalla. Al trabajar con Axios, me he encontrado con que si no indico el formato en el que voy a recibir el archivo, hace un formateo por su cuenta que evita que se muestre correctamente, por lo que este caso, en la petición, estoy indicando en la configuración de la llamada, el formato BLOB (Binary Large Object) .
{ responseType: 'blob' }
Y al realizar la petición, y recibir cada uno de los ficheros, podremos ver nuestras imágenes.
Subida de objetos
Se puede dar el caso en el que queramos hacer la subida nosotros por nuestra cuenta, según la documentación, sería la siguiente URL.
POST https://storage.googleapis.com/upload/storage/v1/b/BUCKET_NAME/o
Con unos query param obligatorios, que serían name (nombre del objeto) y uploadType (que puede ser de 3 tipos ⇒ media | multipart | resumable
Una vez preparada la petición, solo tendríamos que pasar el fichero por un formulario y realizarla.
Una vez hecha, si hacemos la petición de obtener los objetos de nuevo, estará añadida.
Conclusiones
En este tutorial hemos abarcado como hacer una pequeña aplicación que interactúa con un bucket de Google Cloud Storage y los pasos previos a interactuar con el mismo. Todo esto se ha hecho en una aplicación de React y sin nada de Back End. No obstante, es importante destacar que esta práctica no es la más recomendada desde el punto de vista de la seguridad, ya que nuestras llamadas a la API de Google quedarían completamente expuestas, lo cual no es deseable. A pesar de que hemos desarrollado todo el proceso únicamente en una aplicación Front End, los pasos que hemos seguido para la interacción con el bucket de Google Cloud Storage, ajustando algunas especificidades técnicas, ofrecen una perspectiva de cómo podría llevarse a cabo este procedimiento en el Back End.