roble 1.4.0 copy "roble: ^1.4.0" to clipboard
roble: ^1.4.0 copied to clipboard

Cliente Flutter para la plataforma ROBLE de Uninorte OpenLab. Autenticación y CRUD sobre bases de datos PostgreSQL.

roble #

Cliente de Flutter para Roble, la plataforma de Uninorte OpenLab.

Con este paquete tu app puede tener cuentas de usuario, guardar datos y enterarse de los cambios al momento, sin que escribas backend.


Instalación #

flutter pub add roble

En Android, abre android/app/src/main/AndroidManifest.xml y añade permiso de internet dentro de <manifest>:

<uses-permission android:name="android.permission.INTERNET" />

Tu primer minuto #

Necesitas dos datos de la consola de Roble: la URL y el id de tu proyecto (el «contrato»).

import 'package:roble/roble.dart';

final db = RobleApiDataBase(
  config: RobleApiConfig.fromContract(
    baseUrl: 'https://roble-api.test-openlab.uninorte.edu.co',
    contractId: 'miproyecto_ab12cd34',
  ),
);

// Crear una cuenta
await db.register(
  email: 'ana@correo.com',
  password: 'MiClave!1',
  name: 'Ana García',
);

// Entrar. Devuelve el perfil.
final usuario = await db.login(
  email: 'ana@correo.com',
  password: 'MiClave!1',
);
print('Hola ${usuario['name']}');

Crea db una sola vez en tu app y reutilízalo. Si lo creas de nuevo en cada pantalla, cada copia tendrá su propia sesión.


Cuentas de usuario #

Entrar y salir #

await db.login(email: correo, password: clave);
await db.logout();

if (db.isLoggedIn) print('Hay alguien dentro');

final perfil = await db.currentUser();

Que la sesión sobreviva a cerrar la app #

Por omisión la sesión se guarda en el almacenamiento seguro del teléfono. Al arrancar, pregúntale a Roble si sigue siendo válida:

void main() async {
  WidgetsFlutterBinding.ensureInitialized();

  if (await db.restoreSession()) {
    // Entra directo a la pantalla principal
  } else {
    // Muestra el login
  }
  runApp(MiApp());
}

Registro con código por correo #

Si prefieres confirmar que el correo existe antes de crear la cuenta:

await db.registerWithVerification(
  email: 'ana@correo.com',
  password: 'MiClave!1',
  name: 'Ana García',
);

// Ana recibe un código y lo escribe en tu pantalla
await db.verifyEmail(email: 'ana@correo.com', code: '123456');

resendCode(email: ...) lo manda otra vez si no llegó.

Contraseña olvidada #

await db.forgotPassword(email: 'ana@correo.com');
// Le llega un código por correo
await db.resetPassword(token: '123456', newPassword: 'OtraClave!2');

Entrar con Google #

Una línea:

final usuario = await db.signInWithGoogle();

En móvil sale el selector de cuentas del teléfono. En web se abre una ventana. El paquete elige solo.

Antes tienes que configurar Google en la consola de Roble y registrar allí el «destino de retorno» de tu app. En iOS, además, pasa el Client ID de iOS al crear el cliente:

RobleApiDataBase(
  config: config,
  googleIosClientId: 'xxxx.apps.googleusercontent.com',
  ssoRedirect: 'mi-app-web', // el nombre que registraste en la consola
);

¿Qué proveedores tienes activos? Para pintar solo los botones que funcionan:

for (final p in await db.listProviders()) {
  print(p.displayName); // "Google", "Microsoft"…
}

Guardar datos: tablas #

Una tabla es como una hoja de cálculo: la creas en la consola con sus columnas, y desde la app la llenas.

// Crear
final producto = await db.create('Product', {
  'name': 'Café',
  'quantity': 12,
});

// Leer todo
final todos = await db.read('Product');

// Leer con filtro (igualdad)
final agotados = await db.read('Product', filters: {'quantity': 0});

// Uno solo, por su id
final uno = await db.getById('Product', producto['_id']);

// Cambiar
await db.update('Product', producto['_id'], {'quantity': 11});

// Borrar
await db.delete('Product', producto['_id']);

Cada registro trae un _id que pone Roble. Es lo que usas para cambiarlo o borrarlo.

Varios de golpe #

final res = await db.createMany('Product', [
  {'name': 'Té', 'quantity': 5},
  {'name': 'Pan', 'quantity': 0},
]);
print('Guardados: ${res.inserted.length}, rechazados: ${res.skipped.length}');

Consultas más complicadas #

read solo filtra por igualdad. Para juntar tablas, sumar o paginar, guarda la consulta SQL en la consola y llámala por su nombre:

final res = await db.executeQueryByName('productosSinInventario');
for (final fila in res.rows) print(fila);

Usa el nombre, no el UUID: el nombre sobrevive si recreas la consulta.

Una tabla que todos pueden leer #

Si marcas una tabla como pública en la consola, se puede leer sin haber iniciado sesión:

final catalogo = await db.publicRead('Product');

Ojo: público es público. Cualquiera con el id del proyecto puede leerla.


Guardar datos: árbol JSON #

A veces no vale la pena declarar una tabla: un chat, un tablero, una partida. Para eso está el árbol JSON. No declaras nada: la estructura nace cuando escribes el primer dato.

// Añadir, con clave que genera el servidor
final id = await db.json.push('mensajes', {
  'texto': 'hola',
  'de': 'ana@correo.com',
});

// Leer la colección entera
final todos = await db.json.read('mensajes');

// Cambiar solo una clave
await db.json.update('mensajes/$id', {'leido': true});

// Borrar
await db.json.remove('mensajes/$id');

Una ruta es coleccion/hijo/nieto. El primer trozo es la colección.

Las claves de push salen ordenadas por tiempo, así que ordenarlas ordena los mensajes — sin depender del reloj de cada teléfono.

¿Tabla o árbol JSON? #

Usa una tabla cuando Usa el árbol JSON cuando
Los datos tienen forma fija La forma cambia o no importa
Quieres consultas SQL Solo lees y escribes por ruta
Son datos del negocio Son datos que van y vienen

Enterarse de los cambios al momento #

Escuchar te avisa cuando otro usuario cambia algo, sin que tengas que recargar.

// Una tabla
final sub = db.watchTable('Product').listen((cambio) {
  print('${cambio.type}: ${cambio.record}');
});

// Un solo registro
db.watchRecord('Product', id).listen((cambio) { ... });

// El árbol JSON
db.json.watch('mensajes').listen((cambio) {
  // En un push, `record` trae {claveNueva: dato}
  cambio.record?.forEach((id, dato) => print(dato));
});

// Al salir de la pantalla
await sub.cancel();

Tres cosas que conviene saber:

  • No trae lo que ya existe, solo lo que cambie de ahora en adelante. Para pintar la lista, léela primero y aplica encima lo que llegue.
  • Cancela al salir de la pantalla. Si no, el socket sigue abierto.
  • Hace falta sesión iniciada.

Puedes pedir solo algunos cambios, o filtrar en el servidor:

db.watchTable(
  'Product',
  events: [RobleChangeType.insert],
  filters: [RobleFilter('quantity', 'eq', 0)],
).listen(...);

Filtrar aquí ahorra el viaje de todo lo que no te interesa.


Cuando algo falla #

Todo lanza alguna subclase de RobleApiException:

try {
  await db.login(email: correo, password: clave);
} on RobleApiHttpException catch (e) {
  if (e.statusCode == 401) mostrar('Correo o contraseña incorrectos');
} on RobleApiNetworkException {
  mostrar('Sin conexión');
} on RobleApiException catch (e) {
  mostrar(e.message);
}
Excepción Qué pasó
RobleApiHttpException El servidor respondió con error. Mira statusCode
RobleApiNetworkException No se pudo llegar al servidor
RobleApiTimeoutException Tardó demasiado
RobleApiAuthException Problema de sesión o de login social
RobleApiFormatException La respuesta no tenía la forma esperada
RobleApiConflictException Ya existe una cuenta con ese correo

Los números que más vas a ver:

  • 401 — no hay sesión, o las credenciales están mal.
  • 403 — la tabla no es pública (en publicRead).
  • 404 — no existe esa consulta guardada.

Referencia rápida #

Sesión · isLoggedIn · restoreSession() · logout()

Cuentas · register() · registerWithVerification() · verifyEmail() · resendCode() · login() · currentUser() · forgotPassword() · resetPassword() · deleteAccount()

Login social · signInWithGoogle() · signInWithProvider() · signInWithIdToken() · listProviders() · providerClientId() · startSocialLogin() · exchangeSocialCode() · isSocialCallback()

Tablas · create() · createMany() · read() · getById() · update() · delete() · publicRead() · executeQuery() · executeQueryByName()

Árbol JSON · json.collections() · json.read() · json.write() · json.update() · json.push() · json.remove() · json.watch()

Tiempo real · watchTable() · watchRecord() · realtimePolicies() · realtimePolicy() · setRealtimePolicy() · disableRealtime()


Licencia #

MIT

1
likes
0
points
321
downloads

Publisher

unverified uploader

Weekly Downloads

Cliente Flutter para la plataforma ROBLE de Uninorte OpenLab. Autenticación y CRUD sobre bases de datos PostgreSQL.

Repository (GitHub)
View/report issues

License

unknown (license)

Dependencies

crypto, flutter, flutter_secure_storage, flutter_web_auth_2, google_sign_in, http, socket_io_client, web

More

Packages that depend on roble