Bienvenido a la Documentación de Google Drive API v3

📌 Información: La API de Google Drive v3 permite a las aplicaciones acceder y manipular archivos en Google Drive mediante solicitudes HTTP RESTful.

¿Qué puedes hacer con esta API?

  • ✅ Crear, leer, actualizar y eliminar archivos
  • ✅ Gestionar permisos y compartir archivos
  • ✅ Buscar archivos con consultas avanzadas
  • ✅ Trabajar con carpetas y estructuras jerárquicas
  • ✅ Sincronizar cambios en tiempo real
  • ✅ Gestionar comentarios y revisiones
  • ✅ Integrar con Shared Drives (Team Drives)

Características Principales

📤 Subir Archivos

Carga archivos de hasta 5TB con soporte para uploads resumibles

🔍 Búsqueda Avanzada

Encuentra archivos con consultas personalizadas y filtros

🔐 Control de Acceso

Gestiona permisos granulares para usuarios y grupos

🔄 Sincronización

Mantén tus aplicaciones actualizadas con webhooks

Base URL

https://www.googleapis.com/drive/v3/
✨ Consejo: Utiliza el menú lateral para navegar por los diferentes recursos y endpoints disponibles. Cada sección incluye ejemplos de código en múltiples lenguajes.

⚡ Inicio Rápido

Pasos para Comenzar

  1. Crear un proyecto en Google Cloud Console
  2. Habilitar la API de Google Drive
  3. Crear credenciales OAuth 2.0
  4. Configurar el consentimiento de OAuth
  5. Hacer tu primera solicitud

Primer Ejemplo: Listar Archivos

// Listar los primeros 10 archivos
const accessToken = 'YOUR_ACCESS_TOKEN';

fetch('https://www.googleapis.com/drive/v3/files?pageSize=10', {
  headers: {
    'Authorization': `Bearer ${accessToken}`
  }
})
.then(response => response.json())
.then(data => {
  console.log('Archivos:', data.files);
  data.files.forEach(file => {
    console.log(`${file.name} (${file.id})`);
  });
})
.catch(error => console.error('Error:', error));
from google.oauth2.credentials import Credentials
from googleapiclient.discovery import build

# Configurar credenciales
creds = Credentials(token='YOUR_ACCESS_TOKEN')
service = build('drive', 'v3', credentials=creds)

# Listar archivos
results = service.files().list(
    pageSize=10,
    fields="files(id, name, mimeType)"
).execute()

files = results.get('files', [])
for file in files:
    print(f"{file['name']} ({file['id']})")
curl -X GET \
  'https://www.googleapis.com/drive/v3/files?pageSize=10' \
  -H 'Authorization: Bearer YOUR_ACCESS_TOKEN' \
  -H 'Content-Type: application/json'
⚠️ Importante: Nunca expongas tu access token en código del lado del cliente. Utiliza un backend para manejar la autenticación de forma segura.

🔐 Autenticación OAuth 2.0

Scopes Disponibles

Los scopes definen los permisos que tu aplicación necesita. Solicita solo los scopes necesarios.

Scope Descripción
https://www.googleapis.com/auth/drive Acceso completo a todos los archivos
https://www.googleapis.com/auth/drive.file Solo archivos creados por la app
https://www.googleapis.com/auth/drive.readonly Solo lectura de archivos
https://www.googleapis.com/auth/drive.metadata Ver y modificar metadatos
https://www.googleapis.com/auth/drive.metadata.readonly Solo lectura de metadatos
https://www.googleapis.com/auth/drive.appdata Acceso a carpeta de datos de la app

Flujo de Autenticación

// Ejemplo de autenticación con Google OAuth2
const CLIENT_ID = 'your-client-id.apps.googleusercontent.com';
const REDIRECT_URI = 'http://localhost:3000/callback';
const SCOPE = 'https://www.googleapis.com/auth/drive.file';

// Paso 1: Redirigir al usuario a la página de autorización
const authUrl = `https://accounts.google.com/o/oauth2/v2/auth?` +
  `client_id=${CLIENT_ID}&` +
  `redirect_uri=${REDIRECT_URI}&` +
  `response_type=code&` +
  `scope=${SCOPE}&` +
  `access_type=offline`;

window.location.href = authUrl;

// Paso 2: Intercambiar el código por tokens (en tu backend)
const response = await fetch('https://oauth2.googleapis.com/token', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    code: authorizationCode,
    client_id: CLIENT_ID,
    client_secret: CLIENT_SECRET,
    redirect_uri: REDIRECT_URI,
    grant_type: 'authorization_code'
  })
});

const { access_token, refresh_token } = await response.json();

📄 Files - Gestión de Archivos

El recurso Files es el más importante de la API. Permite crear, leer, actualizar y eliminar archivos en Google Drive.

GET files.list

Lista los archivos del usuario con opciones de filtrado y paginación.

Parámetros de Consulta

Parámetro Tipo Descripción
pageSize integer Número máximo de archivos por página (1-1000, default: 100)
pageToken string Token para continuar con la siguiente página
q string Consulta de búsqueda (ej: "name contains 'invoice'")
orderBy string Ordenar por: createdTime, folder, modifiedTime, name, etc.
spaces string Espacios a consultar: 'drive', 'appDataFolder'
// Buscar archivos PDF modificados recientemente
const query = "mimeType='application/pdf' and modifiedTime > '2024-01-01T00:00:00'";

const response = await fetch(
  `https://www.googleapis.com/drive/v3/files?q=${encodeURIComponent(query)}&orderBy=modifiedTime desc&pageSize=20`,
  {
    headers: {
      'Authorization': `Bearer ${accessToken}`
    }
  }
);

const data = await response.json();
console.log('Archivos encontrados:', data.files);
query = "mimeType='application/pdf' and modifiedTime > '2024-01-01T00:00:00'"

results = service.files().list(
    q=query,
    orderBy='modifiedTime desc',
    pageSize=20,
    fields='files(id, name, mimeType, modifiedTime)'
).execute()

files = results.get('files', [])
print(f'Encontrados {len(files)} archivos')
curl -X GET \
  'https://www.googleapis.com/drive/v3/files?q=mimeType%3D%27application%2Fpdf%27&orderBy=modifiedTime%20desc&pageSize=20' \
  -H 'Authorization: Bearer YOUR_ACCESS_TOKEN'

POST files.create

Crea un nuevo archivo o carpeta en Google Drive.

Crear una Carpeta

// Crear una nueva carpeta
const metadata = {
  name: 'Mi Nueva Carpeta',
  mimeType: 'application/vnd.google-apps.folder'
};

const response = await fetch('https://www.googleapis.com/drive/v3/files', {
  method: 'POST',
  headers: {
    'Authorization': `Bearer ${accessToken}`,
    'Content-Type': 'application/json'
  },
  body: JSON.stringify(metadata)
});

const folder = await response.json();
console.log('Carpeta creada:', folder.id);
folder_metadata = {
    'name': 'Mi Nueva Carpeta',
    'mimeType': 'application/vnd.google-apps.folder'
}

folder = service.files().create(
    body=folder_metadata,
    fields='id, name'
).execute()

print(f'Carpeta creada: {folder.get("id")}')
curl -X POST \
  'https://www.googleapis.com/drive/v3/files' \
  -H 'Authorization: Bearer YOUR_ACCESS_TOKEN' \
  -H 'Content-Type: application/json' \
  -d '{
    "name": "Mi Nueva Carpeta",
    "mimeType": "application/vnd.google-apps.folder"
  }'

Subir un Archivo

// Subir un archivo con contenido
const fileContent = 'Contenido del archivo';
const metadata = {
  name: 'documento.txt',
  mimeType: 'text/plain'
};

const form = new FormData();
form.append('metadata', new Blob([JSON.stringify(metadata)], { type: 'application/json' }));
form.append('file', new Blob([fileContent], { type: 'text/plain' }));

const response = await fetch('https://www.googleapis.com/upload/drive/v3/files?uploadType=multipart', {
  method: 'POST',
  headers: { 'Authorization': `Bearer ${accessToken}` },
  body: form
});

const file = await response.json();
console.log('Archivo subido:', file.id);
from googleapiclient.http import MediaFileUpload

file_metadata = {'name': 'documento.txt'}
media = MediaFileUpload('local_file.txt', mimetype='text/plain')

file = service.files().create(
    body=file_metadata,
    media_body=media,
    fields='id, name'
).execute()

print(f'Archivo subido: {file.get("id")}')

GET files.get

Obtiene los metadatos o el contenido de un archivo por su ID.

// Obtener metadatos de un archivo
const fileId = '1abc...xyz';
const fields = 'id,name,mimeType,createdTime,modifiedTime,size,owners';

const response = await fetch(
  `https://www.googleapis.com/drive/v3/files/${fileId}?fields=${fields}`,
  { headers: { 'Authorization': `Bearer ${accessToken}` }}
);

const fileMetadata = await response.json();
console.log('Metadatos:', fileMetadata);
file_id = '1abc...xyz'
file = service.files().get(
    fileId=file_id,
    fields='id,name,mimeType,createdTime,modifiedTime,size,owners'
).execute()

print(f'Archivo: {file.get("name")}')

PATCH files.update

Actualiza los metadatos o el contenido de un archivo.

// Renombrar un archivo
const fileId = '1abc...xyz';
const newMetadata = { name: 'nuevo_nombre.txt' };

const response = await fetch(
  `https://www.googleapis.com/drive/v3/files/${fileId}`,
  {
    method: 'PATCH',
    headers: {
      'Authorization': `Bearer ${accessToken}`,
      'Content-Type': 'application/json'
    },
    body: JSON.stringify(newMetadata)
  }
);

const updated = await response.json();
console.log('Archivo actualizado:', updated.name);

DELETE files.delete

Elimina permanentemente un archivo (sin mover a la papelera).

⚠️ Cuidado: Esta operación es irreversible. Para mover a la papelera, usa files.update con trashed: true.
// Eliminar un archivo permanentemente
const fileId = '1abc...xyz';

await fetch(`https://www.googleapis.com/drive/v3/files/${fileId}`, {
  method: 'DELETE',
  headers: { 'Authorization': `Bearer ${accessToken}` }
});

console.log('Archivo eliminado');

👥 Permissions - Gestión de Permisos

Los permisos controlan quién puede acceder a tus archivos y qué pueden hacer con ellos.

Tipos de Permisos

Rol Descripción
owner Propietario del archivo con control total
organizer Organizador (solo para shared drives)
fileOrganizer Organizador de archivos (solo para shared drives)
writer Puede editar y comentar
commenter Puede ver y comentar
reader Solo puede ver

POST permissions.create

Crea un permiso para compartir un archivo con un usuario, grupo o hacer público.

Compartir con un Usuario Específico

// Compartir archivo con un usuario
const fileId = '1abc...xyz';
const permission = {
  type: 'user',
  role: 'writer',
  emailAddress: 'usuario@example.com'
};

const response = await fetch(
  `https://www.googleapis.com/drive/v3/files/${fileId}/permissions`,
  {
    method: 'POST',
    headers: {
      'Authorization': `Bearer ${accessToken}`,
      'Content-Type': 'application/json'
    },
    body: JSON.stringify(permission)
  }
);

const perm = await response.json();
console.log('Permiso creado:', perm.id);
permission = {
    'type': 'user',
    'role': 'writer',
    'emailAddress': 'usuario@example.com'
}

result = service.permissions().create(
    fileId=file_id,
    body=permission,
    fields='id'
).execute()

print(f'Permiso creado: {result.get("id")}')

Hacer un Archivo Público

// Hacer un archivo público (cualquiera con el enlace puede ver)
const fileId = '1abc...xyz';
const publicPermission = {
  type: 'anyone',
  role: 'reader'
};

await fetch(
  `https://www.googleapis.com/drive/v3/files/${fileId}/permissions`,
  {
    method: 'POST',
    headers: {
      'Authorization': `Bearer ${accessToken}`,
      'Content-Type': 'application/json'
    },
    body: JSON.stringify(publicPermission)
  }
);

console.log('Archivo ahora es público');

GET permissions.list

Lista todos los permisos de un archivo.

const fileId = '1abc...xyz';

const response = await fetch(
  `https://www.googleapis.com/drive/v3/files/${fileId}/permissions`,
  { headers: { 'Authorization': `Bearer ${accessToken}` }}
);

const data = await response.json();
data.permissions.forEach(perm => {
  console.log(`${perm.emailAddress}: ${perm.role}`);
});

DELETE permissions.delete

Elimina un permiso de un archivo.

const fileId = '1abc...xyz';
const permissionId = 'permission123';

await fetch(
  `https://www.googleapis.com/drive/v3/files/${fileId}/permissions/${permissionId}`,
  {
    method: 'DELETE',
    headers: { 'Authorization': `Bearer ${accessToken}` }
  }
);

console.log('Permiso eliminado');

💬 Comments - Gestión de Comentarios

POST comments.create

Crea un comentario en un archivo.

const fileId = '1abc...xyz';
const comment = {
  content: 'Este es un comentario de ejemplo'
};

const response = await fetch(
  `https://www.googleapis.com/drive/v3/files/${fileId}/comments`,
  {
    method: 'POST',
    headers: {
      'Authorization': `Bearer ${accessToken}`,
      'Content-Type': 'application/json'
    },
    body: JSON.stringify(comment)
  }
);

const newComment = await response.json();
console.log('Comentario creado:', newComment.id);

GET comments.list

Lista todos los comentarios de un archivo.

const fileId = '1abc...xyz';

const response = await fetch(
  `https://www.googleapis.com/drive/v3/files/${fileId}/comments`,
  { headers: { 'Authorization': `Bearer ${accessToken}` }}
);

const data = await response.json();
data.comments.forEach(comment => {
  console.log(`${comment.author.displayName}: ${comment.content}`);
});

↩️ Replies - Respuestas a Comentarios

POST replies.create

Crea una respuesta a un comentario.

const fileId = '1abc...xyz';
const commentId = 'comment123';
const reply = {
  content: 'Esta es una respuesta al comentario'
};

const response = await fetch(
  `https://www.googleapis.com/drive/v3/files/${fileId}/comments/${commentId}/replies`,
  {
    method: 'POST',
    headers: {
      'Authorization': `Bearer ${accessToken}`,
      'Content-Type': 'application/json'
    },
    body: JSON.stringify(reply)
  }
);

const newReply = await response.json();
console.log('Respuesta creada:', newReply.id);

📋 Revisions - Historial de Versiones

Las revisiones permiten acceder al historial de cambios de un archivo.

GET revisions.list

Lista todas las revisiones de un archivo.

const fileId = '1abc...xyz';

const response = await fetch(
  `https://www.googleapis.com/drive/v3/files/${fileId}/revisions`,
  { headers: { 'Authorization': `Bearer ${accessToken}` }}
);

const data = await response.json();
data.revisions.forEach(rev => {
  console.log(`Revisión ${rev.id}: ${rev.modifiedTime}`);
});

GET revisions.get

Obtiene una revisión específica de un archivo.

const fileId = '1abc...xyz';
const revisionId = 'revision123';

const response = await fetch(
  `https://www.googleapis.com/drive/v3/files/${fileId}/revisions/${revisionId}`,
  { headers: { 'Authorization': `Bearer ${accessToken}` }}
);

const revision = await response.json();
console.log('Revisión:', revision);

🗂️ Drives - Shared Drives (Team Drives)

Los Shared Drives (anteriormente Team Drives) permiten a equipos colaborar en archivos de forma organizada.

GET drives.list

Lista los shared drives del usuario.

const response = await fetch(
  'https://www.googleapis.com/drive/v3/drives',
  { headers: { 'Authorization': `Bearer ${accessToken}` }}
);

const data = await response.json();
data.drives.forEach(drive => {
  console.log(`${drive.name} (${drive.id})`);
});

POST drives.create

Crea un nuevo shared drive.

const driveMetadata = {
  name: 'Mi Equipo de Trabajo'
};

const requestId = crypto.randomUUID(); // ID único para idempotencia

const response = await fetch(
  `https://www.googleapis.com/drive/v3/drives?requestId=${requestId}`,
  {
    method: 'POST',
    headers: {
      'Authorization': `Bearer ${accessToken}`,
      'Content-Type': 'application/json'
    },
    body: JSON.stringify(driveMetadata)
  }
);

const drive = await response.json();
console.log('Shared Drive creado:', drive.id);

🔄 Changes - Sincronización de Cambios

El recurso Changes permite detectar cambios en archivos y carpetas para mantener tu aplicación sincronizada.

GET changes.getStartPageToken

Obtiene el token inicial para comenzar a monitorear cambios.

const response = await fetch(
  'https://www.googleapis.com/drive/v3/changes/startPageToken',
  { headers: { 'Authorization': `Bearer ${accessToken}` }}
);

const data = await response.json();
const pageToken = data.startPageToken;
console.log('Start token:', pageToken);

GET changes.list

Lista los cambios ocurridos desde un pageToken específico.

const pageToken = 'your_page_token';

const response = await fetch(
  `https://www.googleapis.com/drive/v3/changes?pageToken=${pageToken}`,
  { headers: { 'Authorization': `Bearer ${accessToken}` }}
);

const data = await response.json();
data.changes.forEach(change => {
  console.log(`Cambio en archivo: ${change.fileId}`);
  console.log(`Tipo: ${change.type}`);
});

// Guardar el nuevo pageToken para la próxima consulta
const newPageToken = data.newStartPageToken;
console.log('Nuevo token:', newPageToken);

ℹ️ About - Información del Usuario

GET about.get

Obtiene información sobre el usuario, su Drive y capacidades del sistema.

const response = await fetch(
  'https://www.googleapis.com/drive/v3/about?fields=user,storageQuota,canCreateDrives',
  { headers: { 'Authorization': `Bearer ${accessToken}` }}
);

const data = await response.json();
console.log('Usuario:', data.user.displayName);
console.log('Espacio usado:', data.storageQuota.usage);
console.log('Límite:', data.storageQuota.limit);

🎯 Apps - Aplicaciones Instaladas

GET apps.list

Lista las aplicaciones instaladas por el usuario.

const response = await fetch(
  'https://www.googleapis.com/drive/v3/apps',
  { headers: { 'Authorization': `Bearer ${accessToken}` }}
);

const data = await response.json();
data.items.forEach(app => {
  console.log(`${app.name}: ${app.id}`);
});

📡 Channels - Notificaciones Push

Los canales permiten recibir notificaciones push cuando ocurren cambios en recursos.

POST files.watch

Suscríbete a cambios en un archivo específico.

const fileId = '1abc...xyz';
const channel = {
  id: crypto.randomUUID(),
  type: 'web_hook',
  address: 'https://tu-servidor.com/webhook'
};

const response = await fetch(
  `https://www.googleapis.com/drive/v3/files/${fileId}/watch`,
  {
    method: 'POST',
    headers: {
      'Authorization': `Bearer ${accessToken}`,
      'Content-Type': 'application/json'
    },
    body: JSON.stringify(channel)
  }
);

const watchChannel = await response.json();
console.log('Canal creado:', watchChannel.id);

POST channels.stop

Detiene un canal de notificaciones.

const channel = {
  id: 'channel-id',
  resourceId: 'resource-id'
};

await fetch('https://www.googleapis.com/drive/v3/channels/stop', {
  method: 'POST',
  headers: {
    'Authorization': `Bearer ${accessToken}`,
    'Content-Type': 'application/json'
  },
  body: JSON.stringify(channel)
});

console.log('Canal detenido');

🔓 Access Proposals - Solicitudes de Acceso

GET accessproposals.list

Lista las solicitudes de acceso pendientes para un archivo.

const fileId = '1abc...xyz';

const response = await fetch(
  `https://www.googleapis.com/drive/v3/files/${fileId}/accessproposals`,
  { headers: { 'Authorization': `Bearer ${accessToken}` }}
);

const data = await response.json();
data.accessProposals.forEach(proposal => {
  console.log(`Solicitud de: ${proposal.requester.emailAddress}`);
});

⚠️ Errores Comunes y Soluciones

Códigos de Error HTTP

Código Mensaje Solución
401 Unauthorized El token de acceso no es válido o ha expirado. Renueva el token.
403 Forbidden No tienes permisos suficientes. Verifica los scopes y permisos del archivo.
404 Not Found El archivo no existe o no tienes acceso a él.
429 Too Many Requests Has excedido los límites de tasa. Implementa exponential backoff.
500 Internal Server Error Error del servidor de Google. Reintenta la solicitud después de un delay.

Errores Comunes

1. "Invalid Credentials"

Problema: El token de acceso no es válido.
Solución: Asegúrate de que estás usando el token correcto y que no ha expirado. Usa el refresh token para obtener uno nuevo.

2. "Insufficient Permissions"

Problema: Los scopes solicitados no son suficientes.
Solución: Solicita los scopes adecuados durante la autenticación. Por ejemplo, necesitas drive.file o drive para crear archivos.

3. "File not found"

Problema: El archivo no existe o fue eliminado.
Solución: Verifica que el ID del archivo sea correcto y que el usuario tenga acceso.

4. "Rate Limit Exceeded"

Problema: Demasiadas solicitudes en poco tiempo.
Solución: Implementa exponential backoff con reintento.
// Implementación de Exponential Backoff
async function fetchWithRetry(url, options, maxRetries = 3) {
  for (let i = 0; i < maxRetries; i++) {
    try {
      const response = await fetch(url, options);
      
      if (response.status === 429) {
        const delay = Math.pow(2, i) * 1000; // 1s, 2s, 4s
        console.log(`Rate limit. Esperando ${delay}ms...`);
        await new Promise(resolve => setTimeout(resolve, delay));
        continue;
      }
      
      if (!response.ok) {
        throw new Error(`HTTP ${response.status}: ${response.statusText}`);
      }
      
      return await response.json();
    } catch (error) {
      if (i === maxRetries - 1) throw error;
    }
  }
}

📊 Límites y Cuotas

Límites de Tasa

Recurso Límite
Solicitudes por usuario por 100 segundos 1,000 solicitudes
Solicitudes por proyecto por 100 segundos 10,000 solicitudes
Tamaño máximo de archivo (upload simple) 5 MB
Tamaño máximo de archivo (upload resumible) 5 TB
Archivos compartidos con un usuario Ilimitado
Revisiones por archivo 200 (kept forever)

Cuotas de Almacenamiento

  • Google Drive gratuito: 15 GB compartidos con Gmail y Google Photos
  • Google One: De 100 GB a 2 TB
  • Google Workspace: Variable según el plan (30 GB - ilimitado)
💡 Nota: Los archivos de Google Docs, Sheets, Slides, Forms y Sites no cuentan para la cuota de almacenamiento.

Mejores Prácticas

  • ✅ Implementa exponential backoff para manejar errores 429
  • ✅ Usa campos específicos con el parámetro fields para reducir el tamaño de respuestas
  • ✅ Almacena en caché los resultados cuando sea posible
  • ✅ Usa batch requests para múltiples operaciones
  • ✅ Implementa paginación adecuada para listas grandes
  • ✅ Usa uploads resumibles para archivos grandes

💡 Ejemplos Prácticos

Ejemplo 1: Sistema de Backup Automático

Crea una carpeta de backup y sube archivos automáticamente.

async function createBackupSystem(accessToken) {
  // 1. Crear carpeta de backup
  const folderMetadata = {
    name: `Backup_${new Date().toISOString().split('T')[0]}`,
    mimeType: 'application/vnd.google-apps.folder'
  };
  
  const folderResponse = await fetch('https://www.googleapis.com/drive/v3/files', {
    method: 'POST',
    headers: {
      'Authorization': `Bearer ${accessToken}`,
      'Content-Type': 'application/json'
    },
    body: JSON.stringify(folderMetadata)
  });
  
  const folder = await folderResponse.json();
  console.log('Carpeta creada:', folder.id);
  
  // 2. Subir archivos a la carpeta
  async function uploadFile(fileName, fileContent) {
    const metadata = {
      name: fileName,
      parents: [folder.id]
    };
    
    const form = new FormData();
    form.append('metadata', new Blob([JSON.stringify(metadata)], { type: 'application/json' }));
    form.append('file', new Blob([fileContent]));
    
    const response = await fetch(
      'https://www.googleapis.com/upload/drive/v3/files?uploadType=multipart',
      {
        method: 'POST',
        headers: { 'Authorization': `Bearer ${accessToken}` },
        body: form
      }
    );
    
    return await response.json();
  }
  
  // Subir archivos
  const files = ['config.json', 'database.sql', 'logs.txt'];
  for (const file of files) {
    const result = await uploadFile(file, `Contenido de ${file}`);
    console.log(`${file} subido: ${result.id}`);
  }
  
  return folder.id;
}

Ejemplo 2: Búsqueda Avanzada de Archivos

Busca archivos con múltiples criterios y filtros.

async function advancedSearch(accessToken, criteria) {
  const queries = [];
  
  // Filtro por nombre
  if (criteria.name) {
    queries.push(`name contains '${criteria.name}'`);
  }
  
  // Filtro por tipo MIME
  if (criteria.mimeType) {
    queries.push(`mimeType='${criteria.mimeType}'`);
  }
  
  // Filtro por fecha de modificación
  if (criteria.modifiedAfter) {
    queries.push(`modifiedTime > '${criteria.modifiedAfter}'`);
  }
  
  // Excluir archivos en papelera
  queries.push('trashed=false');
  
  const query = queries.join(' and ');
  
  const response = await fetch(
    `https://www.googleapis.com/drive/v3/files?q=${encodeURIComponent(query)}&orderBy=modifiedTime desc`,
    { headers: { 'Authorization': `Bearer ${accessToken}` }}
  );
  
  const data = await response.json();
  return data.files;
}

// Uso
const results = await advancedSearch(accessToken, {
  name: 'reporte',
  mimeType: 'application/pdf',
  modifiedAfter: '2024-01-01T00:00:00'
});

console.log(`Encontrados ${results.length} archivos`);

Ejemplo 3: Compartir Archivo con Múltiples Usuarios

Comparte un archivo con varios usuarios de una vez.

async function shareWithMultipleUsers(accessToken, fileId, users) {
  const results = [];
  
  for (const user of users) {
    const permission = {
      type: 'user',
      role: user.role || 'reader',
      emailAddress: user.email
    };
    
    try {
      const response = await fetch(
        `https://www.googleapis.com/drive/v3/files/${fileId}/permissions?sendNotificationEmail=true`,
        {
          method: 'POST',
          headers: {
            'Authorization': `Bearer ${accessToken}`,
            'Content-Type': 'application/json'
          },
          body: JSON.stringify(permission)
        }
      );
      
      const result = await response.json();
      results.push({ email: user.email, success: true, permissionId: result.id });
    } catch (error) {
      results.push({ email: user.email, success: false, error: error.message });
    }
  }
  
  return results;
}

// Uso
const users = [
  { email: 'usuario1@example.com', role: 'writer' },
  { email: 'usuario2@example.com', role: 'reader' },
  { email: 'usuario3@example.com', role: 'commenter' }
];

const shareResults = await shareWithMultipleUsers(accessToken, fileId, users);
shareResults.forEach(r => {
  console.log(`${r.email}: ${r.success ? '✓ Compartido' : '✗ Error'}`);
});

Ejemplo 4: Monitorear Cambios en Tiempo Real

Detecta cambios en archivos usando el API de Changes.

class DriveChangeMonitor {
  constructor(accessToken) {
    this.accessToken = accessToken;
    this.pageToken = null;
  }
  
  async initialize() {
    const response = await fetch(
      'https://www.googleapis.com/drive/v3/changes/startPageToken',
      { headers: { 'Authorization': `Bearer ${this.accessToken}` }}
    );
    const data = await response.json();
    this.pageToken = data.startPageToken;
    console.log('Monitor inicializado con token:', this.pageToken);
  }
  
  async checkForChanges() {
    if (!this.pageToken) {
      await this.initialize();
    }
    
    const response = await fetch(
      `https://www.googleapis.com/drive/v3/changes?pageToken=${this.pageToken}&includeRemoved=true`,
      { headers: { 'Authorization': `Bearer ${this.accessToken}` }}
    );
    
    const data = await response.json();
    
    if (data.changes && data.changes.length > 0) {
      console.log(`Detectados ${data.changes.length} cambios:`);
      data.changes.forEach(change => {
        if (change.removed) {
          console.log(`❌ Archivo eliminado: ${change.fileId}`);
        } else if (change.file) {
          console.log(`📝 Archivo modificado: ${change.file.name}`);
        }
      });
    }
    
    // Actualizar el token para la próxima verificación
    this.pageToken = data.newStartPageToken || data.nextPageToken;
    
    return data.changes || [];
  }
  
  async startMonitoring(intervalMs = 30000) {
    console.log('Iniciando monitoreo de cambios...');
    await this.initialize();
    
    setInterval(async () => {
      await this.checkForChanges();
    }, intervalMs);
  }
}

// Uso
const monitor = new DriveChangeMonitor(accessToken);
await monitor.startMonitoring(30000); // Verificar cada 30 segundos

Ejemplo 5: Gestión de Carpetas Jerarquicas

Crea una estructura de carpetas organizada.

async function createFolderStructure(accessToken, structure, parentId = null) {
  const results = {};
  
  for (const [folderName, subfolders] of Object.entries(structure)) {
    // Crear carpeta
    const metadata = {
      name: folderName,
      mimeType: 'application/vnd.google-apps.folder'
    };
    
    if (parentId) {
      metadata.parents = [parentId];
    }
    
    const response = await fetch(
      'https://www.googleapis.com/drive/v3/files',
      {
        method: 'POST',
        headers: {
          'Authorization': `Bearer ${accessToken}`,
          'Content-Type': 'application/json'
        },
        body: JSON.stringify(metadata)
      }
    );
    
    const folder = await response.json();
    results[folderName] = folder.id;
    console.log(`✓ Carpeta creada: ${folderName}`);
    
    // Crear subcarpetas recursivamente
    if (subfolders && typeof subfolders === 'object') {
      const subResults = await createFolderStructure(accessToken, subfolders, folder.id);
      results[folderName] = { id: folder.id, children: subResults };
    }
  }
  
  return results;
}

// Uso: Crear estructura de proyecto
const projectStructure = {
  'Mi Proyecto': {
    'Documentación': {
      'API': {},
      'Guías': {}
    },
    'Código': {
      'Frontend': {},
      'Backend': {}
    },
    'Recursos': {
      'Imágenes': {},
      'Videos': {}
    }
  }
};

const folderIds = await createFolderStructure(accessToken, projectStructure);
console.log('Estructura creada:', folderIds);