Sheets
Conexión de Google Sheets con Node.js usando una Cuenta de Servicio
1. Configuración en Google Cloud Console
-
Crea un proyecto en Google Cloud Console :
-
Ve a Google Cloud Console.
-
Crea un nuevo proyecto o selecciona uno existente.
-
Activa la API de Google Sheets :
-
Ve a "APIs y Servicios" → "Biblioteca".
-
Busca y habilita la API de Google Sheets .
-
Crea una cuenta de servicio :
-
Ve a "APIs y Servicios" → "Credenciales".
- Haz clic en "Crear credenciales" → "Cuenta de servicio".
-
Asigna un nombre y selecciona el rol
Editor. -
Descarga la clave JSON :
-
Una vez creada la cuenta de servicio, selecciona la cuenta.
- Haz clic en "Claves" → "Agregar clave" → "JSON".
- Descarga el archivo JSON y guárdalo en tu proyecto Node.js (e.g.,
creds.json).
2. Configura el Acceso a la Hoja de Cálculo
- Abre tu hoja de cálculo en Google Sheets .
-
Comparte el acceso con la cuenta de servicio :
-
Encuentra el correo electrónico de la cuenta de servicio en el archivo JSON (propiedad
client_email). - Comparte la hoja de cálculo con este correo (
editoroviewer, según sea necesario).
3. Configuración en Node.js
- Instala las dependencias necesarias :
pnpm add googleapis - Configura la conexión
import { google } from 'googleapis';
import * as fs from 'fs';
// Tipo para la respuesta de valores de una hoja
interface SheetDataResponse {
[key: string]: {
value: string,
cell: string
}[]
}
// Cargar las credenciales de la Service Account
const credentials = JSON.parse(fs.readFileSync('creds.json', 'utf8'));
// Configurar el cliente JWT para la autenticación con la cuenta de servicio
const auth = new google.auth.JWT(
credentials.client_email,
undefined,
credentials.private_key,
['https://www.googleapis.com/auth/spreadsheets']
);
async function authenticate() {
await auth.authorize();
}
// Función para obtener los datos de una hoja de cálculo
export async function read_rows(spreadsheetId: string, range: string): Promise<SheetDataResponse | null> {
await authenticate();
const sheets = google.sheets({ version: 'v4', auth });
const response = await sheets.spreadsheets.values.get({
spreadsheetId: spreadsheetId,
range,
});
// response.data as any || null;
const rows = response.data.values;
if (!rows || rows.length === 0) {
return null; // Retorna null si no hay datos
}
// La primera fila será usada como claves (headers)
const headers = rows[0];
// Inicializamos un objeto donde cada clave será un array de objetos con value y cell
const dataAsObject = {};
headers.forEach((header, colIndex) => {
header = header.toLocaleLowerCase();
dataAsObject[header] = [];
});
// Rellenamos los arrays con objetos que contienen el valor y la referencia de la celda (ej. "A1")
rows.slice(1).forEach((row, rowIndex) => {
headers.forEach((header: string, colIndex) => {
header = header.toLocaleLowerCase();
const cellValue = row[colIndex] || ''; // Valor de la celda o vacío si no hay valor
const cellReference = `${String.fromCharCode(65 + colIndex)}${rowIndex + 2}`; // Convertir columna a letra y fila
dataAsObject[header].push({
value: cellValue,
cell: cellReference
});
});
});
return dataAsObject;
}
// Función para insertar una fila en una hoja de cálculo
export async function add_row(spreadsheetId: string, range: string, values: Record<string, any>): Promise<void> {
await authenticate();
const sheets = google.sheets({ version: 'v4', auth });
await sheets.spreadsheets.values.append({
spreadsheetId,
range,
valueInputOption: 'USER_ENTERED',
requestBody: {
values: [Object.values(values)] //values.map(row => Object.values(row)),
},
});
}
El código de arriba lo puedes editar a tu gusto, el te muestra como leer y insertar datos una vez obtenidas las credenciales de tu service-account.
Acoplando las funciones a nuestro chatbos podriamos crear 2 comandos a modo de darnos una visualización general
import { Workflow } from "@elimeleth/vct-flow"
import { read_rows, add_row } from "./sheet.ts"
export const read_command = new Workflow("read")
.addAction(async (ctx, {send}) => {
const rows = await read_rows();
console.log(rows)
/* todo! aqui coloca tu propia lógica */
});
export const add_command = new Workflow("add")
.addAction(async (ctx, {send}) => {
await add_row(procces.env.SPREAD_SHEET_ID, "test", {
"nombre": "jhon",
"apellido": "doe"
});
/* todo! aqui coloca tu propia lógica */
})