Saltar al contenido principal

Eliminar datos en internet

Cómo utilizar el paquete http para eliminar datos en Internet.

Esta receta cubre cómo eliminar datos a través de internet utilizando el paquete http.

Esta receta utiliza los siguientes pasos:

  1. Agrega el paquete http.
  2. Eliminar datos en el servidor.
  3. Actualizar la pantalla.

1. Agregar el paquete http

#

Para agregar el paquete http como dependencia, ejecuta flutter pub add:

flutter pub add http

Importa el paquete http.

dart
import 'package:http/http.dart' as http;

Si estás haciendo el despliegue en Android, edita tu archivo AndroidManifest.xml para agregar el permiso de Internet.

xml
<!-- Required to fetch data from the internet. -->
<uses-permission android:name="android.permission.INTERNET" />

Del mismo modo, si estás haciendo el despliegue en macOS, edita tus archivos macos/Runner/DebugProfile.entitlements y macos/Runner/Release.entitlements para incluir el entitlement del cliente de red.

xml
<!-- Required to fetch data from the internet. -->
<key>com.apple.security.network.client</key>
<true/>

2. Eliminar datos en el servidor

#

Esta receta cubre cómo eliminar un álbum de JSONPlaceholder utilizando el método http.delete(). Ten en cuenta que esto requiere el id del álbum que deseas eliminar. Para este ejemplo, usa algo que ya conozcas, por ejemplo, id = 1.

dart
Future<http.Response> deleteAlbum(String id) async {
  final http.Response response = await http.delete(
    Uri.parse('https://jsonplaceholder.typicode.com/albums/$id'),
    headers: <String, String>{
      'Content-Type': 'application/json; charset=UTF-8',
    },
  );

  return response;
}

El método http.delete() devuelve un Future que contiene una Response.

  • Future es una clase principal de Dart para trabajar con operaciones asíncronas. Un objeto Future representa un valor potencial o un error que estará disponible en algún momento en el futuro.
  • La clase http.Response contiene los datos recibidos de una llamada http exitosa.
  • El método deleteAlbum() toma un argumento id que es necesario para identificar los datos que se van a eliminar del servidor.

3. Actualizar la pantalla

#

Para verificar si los datos se han eliminado o no, primero obtén los datos de JSONPlaceholder utilizando el método http.get() y muéstralos en la pantalla. (Consulta la receta Obtener datos para ver un ejemplo completo). Ahora deberías tener un botón Eliminar datos que, al presionarlo, llama al método deleteAlbum().

dart
Column(
  mainAxisAlignment: MainAxisAlignment.center,
  children: <Widget>[
    Text(snapshot.data?.title ?? 'Deleted'),
    ElevatedButton(
      child: const Text('Delete Data'),
      onPressed: () {
        setState(() {
          _futureAlbum = deleteAlbum(
            snapshot.data!.id.toString(),
          );
        });
      },
    ),
  ],
);

Ahora, al hacer clic en el botón Eliminar datos, se llama al método deleteAlbum() y el id que estás pasando es el id de los datos que recuperaste de internet. Esto significa que vas a eliminar los mismos datos que obtuviste de internet.

Retornar una respuesta del método deleteAlbum()

#

Una vez que se haya realizado la solicitud de eliminación, puedes devolver una respuesta desde el método deleteAlbum() para notificar a nuestra pantalla que los datos han sido eliminados.

dart
Future<Album> deleteAlbum(String id) async {
  final http.Response response = await http.delete(
    Uri.parse('https://jsonplaceholder.typicode.com/albums/$id'),
    headers: <String, String>{
      'Content-Type': 'application/json; charset=UTF-8',
    },
  );

  if (response.statusCode == 200) {
    // If the server did return a 200 OK response,
    // then return an empty Album. After deleting,
    // you'll get an empty JSON `{}` response.
    // Don't return `null`, otherwise `snapshot.hasData`
    // will always return false on `FutureBuilder`.
    return Album.empty();
  } else {
    // If the server did not return a "200 OK response",
    // then throw an exception.
    throw Exception('Failed to delete album.');
  }
}

FutureBuilder() ahora se vuelve a construir (rebuild) cuando recibe una respuesta. Dado que la respuesta no tendrá ningún dato en su cuerpo si la solicitud fue exitosa, el método Album.fromJson() crea una instancia del objeto Album con un valor por defecto (null en nuestro caso). Este comportamiento se puede alterar de la forma que desees.

¡Eso es todo! Ahora tienes una función que elimina los datos de internet.

Ejemplo completo

#
dart
import 'dart:async';
import 'dart:convert';

import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;

Future<Album> fetchAlbum() async {
  final response = await http.get(
    Uri.parse('https://jsonplaceholder.typicode.com/albums/1'),
  );

  if (response.statusCode == 200) {
    // If the server did return a 200 OK response, then parse the JSON.
    return Album.fromJson(jsonDecode(response.body) as Map<String, dynamic>);
  } else {
    // If the server did not return a 200 OK response, then throw an exception.
    throw Exception('Failed to load album');
  }
}

Future<Album> deleteAlbum(String id) async {
  final http.Response response = await http.delete(
    Uri.parse('https://jsonplaceholder.typicode.com/albums/$id'),
    headers: <String, String>{
      'Content-Type': 'application/json; charset=UTF-8',
    },
  );

  if (response.statusCode == 200) {
    // If the server did return a 200 OK response,
    // then return an empty Album. After deleting,
    // you'll get an empty JSON `{}` response.
    // Don't return `null`, otherwise `snapshot.hasData`
    // will always return false on `FutureBuilder`.
    return Album.empty();
  } else {
    // If the server did not return a "200 OK response",
    // then throw an exception.
    throw Exception('Failed to delete album.');
  }
}

class Album {
  int? id;
  String? title;

  Album({this.id, this.title});

  Album.empty();

  factory Album.fromJson(Map<String, dynamic> json) {
    return switch (json) {
      {'id': int id, 'title': String title} => Album(id: id, title: title),
      _ => throw const FormatException('Failed to load album.'),
    };
  }
}

void main() {
  runApp(const MyApp());
}

class MyApp extends StatefulWidget {
  const MyApp({super.key});

  @override
  State<MyApp> createState() {
    return _MyAppState();
  }
}

class _MyAppState extends State<MyApp> {
  late Future<Album> _futureAlbum;

  @override
  void initState() {
    super.initState();
    _futureAlbum = fetchAlbum();
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Delete Data Example',
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
      ),
      home: Scaffold(
        appBar: AppBar(title: const Text('Delete Data Example')),
        body: Center(
          child: FutureBuilder<Album>(
            future: _futureAlbum,
            builder: (context, snapshot) {
              // If the connection is done,
              // check for response data or an error.
              if (snapshot.connectionState == ConnectionState.done) {
                if (snapshot.hasData) {
                  return Column(
                    mainAxisAlignment: MainAxisAlignment.center,
                    children: <Widget>[
                      Text(snapshot.data?.title ?? 'Deleted'),
                      ElevatedButton(
                        child: const Text('Delete Data'),
                        onPressed: () {
                          setState(() {
                            _futureAlbum = deleteAlbum(
                              snapshot.data!.id.toString(),
                            );
                          });
                        },
                      ),
                    ],
                  );
                } else if (snapshot.hasError) {
                  return Text('${snapshot.error}');
                }
              }

              // By default, show a loading spinner.
              return const CircularProgressIndicator();
            },
          ),
        ),
      ),
    );
  }
}