No tienes acceso a esta clase

¡Continúa aprendiendo! Únete y comienza a potenciar tu carrera

Eliminar recursos con método DELETE en APIs RESTful

10/19
Recursos

¿Cómo eliminar recursos a través de una API REST?

Eliminar recursos en una API REST es un proceso esencial que completa el ciclo CRUD (Crear, Leer, Actualizar, Eliminar). Este proceso se realiza mediante el método HTTP DELETE. Al implementar este método, podemos gestionar eficientemente los datos en nuestros servidores y garantizar que la API sea escalable y manejable en el tiempo.

¿Cómo funciona el método HTTP DELETE?

El método DELETE se utiliza para eliminar un recurso específico de una colección. Aquí hay un proceso general:

  • Verificación de existencia: Antes de intentar eliminar un recurso, es crucial verificar si el recurso existe. Si el recurso no está presente, debemos manejar adecuadamente esta situación, sin intentar una operación fallida.

  • Ejecutar eliminación: Una vez verificado, podemos proceder a eliminar el recurso. En un sistema real, esto implicaría ejecutar un comando SQL para eliminar el registro de la base de datos. Sin embargo, en implementaciones más simples, como un arreglo en la memoria, se puede utilizar una función como unset() en PHP para eliminar la clave directamente.

<?php
// Supongamos que tenemos un arreglo
$libros = ['libro1', 'libro2', 'libro3'];

// Queremos eliminar 'libro1'
if (array_key_exists(0, $libros)) {
    unset($libros[0]);
}

// Verificar que el libro haya sido eliminado
echo count($libros); // Output: 2
?>
  • Retorno del estado: Finalmente, después de la eliminación, la API debería devolver el estado actual de la colección para confirmar que el recurso ha sido efectivamente eliminado.

¿Cuáles son las diferencias con los métodos PUT o POST?

Aunque los métodos PUT, POST y DELETE son parte del ciclo CRUD, cada uno tiene un uso y comportamiento distintos. Aquí algunas diferencias clave:

  • PUT vs DELETE: Mientras PUT reemplaza un recurso existente con uno nuevo, DELETE simplemente elimina el recurso sin reemplazo.

  • POST vs DELETE: POST se usa para crear nuevos recursos o entidades, mientras que DELETE los elimina.

¿Qué considerar al eliminar recursos?

Es importante tener en cuenta varios aspectos al implementar el método DELETE en una API REST:

  • Autorización: No todas las solicitudes a la API deberían poder eliminar recursos. Asegúrate de que solo los usuarios con los permisos adecuados puedan realizar esta acción.

  • Eliminación en cascada: Si el recurso eliminado está vinculado a otros recursos, considera cómo estos vínculos se gestionarán. Podría ser necesario eliminar o actualizar recursos relacionados.

  • Optimización y consistencia: La eliminación en bases de datos de grandes volúmenes de datos debe ser manejada cuidadosamente para evitar bloqueos y problemas de consistencia.

¿Cuál es el siguiente paso?

Con el entendimiento de cómo eliminar recursos usando el método DELETE, el próximo desafío es determinar quién tiene acceso a estas operaciones. La autenticación y autorización robusta son fundamentales para proteger la integridad de tus datos. ¡Te animamos a seguir aprendiendo y profundizando en estos temas críticos para el desarrollo de una API REST segura y eficiente!

Aportes 28

Preguntas 6

Ordenar por:

¿Quieres ver más aportes, preguntas y respuestas de la comunidad?

Código de la clase:

<?php

$allowedResourceTypes = [
    'books',
    'authors',
    'genres'
];

$resourceType = $_GET['resource_type'];

if( !in_array($resourceType, $allowedResourceTypes)){
    die;
}

//Defino los recursos
$books = [
    1 => [
        'titulo' => 'Lo que el viento se llevo',
        'id_autor' => 2,
        'id_genero' => 2,
    ],
    2 => [
        'titulo' => 'La Iliada',
        'id_autor' => 1,
        'id_genero' => 1,
    ],
    3 => [
        'titulo' => 'La Odisea',
        'id_autor' => 1,
        'id_genero' => 1,
    ],
];

// Se indica al cliente que lo que recibirá es un json
header('Content-Type: application/json');
// Levantamos el id del recurso buscado
$resourceId = array_key_exists('resource_id', $_GET) ? $_GET['resource_id']:'';

// Generamos la respuesta asumiendo que el pedido es correcto y devilvemos en formafo json
switch( strtoupper($_SERVER['REQUEST_METHOD']) ) {
    case 'GET':
        // en caso de que no pidan ningun recurso
         if ( empty( $resourceId ) ){
            echo json_encode( $books );
         }else{
             // si llegan a pedir un recurso en especifico
            if( array_key_exists( $resourceId, $books) ){
                echo json_encode( $books[ $resourceId ] );
            }
        }
        break;
    case 'POST':
        $json = file_get_contents('php://input');
        // transformamos el json recibido a un nuevo elemento del arreglo
        $books[] = json_decode($json, true);
        // emitimos hacia la salida la ultima clave del arreglo de los libros
        // echo array_keys( $books )[count($books) -1];
        echo json_encode($books);
        break;
    case 'PUT':
        //validamos que el recurso buscado exista
        if (!empty($resourceId) && array_key_exists($resourceId, $books)){
            // Tomamos la entrada cruda
            $json = file_get_contents('php://input');
             // transformamos el json recibido a un nuevo elemento del arreglo
            $books[$resourceId] = json_decode($json, true);
            // Retornamos la coleccion modificada en formato json
            echo json_encode($books);
        }
        break;
    case 'DELETE':
        // validamos que el recurso exista
        if (!empty($resourceId) && array_key_exists($resourceId, $books)){
            // Eliminamos el recurso
            unset( $books[ $resourceId]);    
            // Aquí verificamos que los cambios se han realizado  
            echo json_encode($books);      
        }
        break;
}



// Inicio el servidor en la terminal 1, aqui le asignamos el puerto 8000
// php -S localhost:8000 server.php

// Terminal 2 ejecutar 
// curl http://localhost:8000 -v
// curl http://localhost:8000/\?resource_type\=books
// curl http://localhost:8000/\?resource_type\=books | jq
// ver la comunicacion a través de los encabezados:
// $ curl http://localhost:8000/\?resource_type\=books -v > /dev/null
// consulta
//$curl "http://localhost:8000?resource_type=books&resource_id=1"
// Método POST
//curl -X 'POST' http://localhost:8000/books -d '{"titulo":"Nuevo Libro","id_autor":1,"id_genero":2}'
// Método Put - el recurso 1 será reemplazado por el libro que estoy creando
// $ curl -X 'PUT' http://localhost:8000/books/1 -d '{"titulo": "Nuevo Libro", "id_autor": 1, "id_genero": 2}'
// Método Delete
// curl -X 'DELETE' http://localhost:8000/books/1
?>

Yo traté de implementar todos los métodos en un API en python usando flask para poder entender co se hacía eso en ese lenguaje. Es algo sencillo pero funciona. Este es el resultado:

    from flask import Flask
    from flask_restful import Api, Resource, reqparse

    app = Flask(__name__)
    api = Api(app)

    malwares = [
        {
            "name" : "spyfocus.js",
            "type" : "adware",
            "media" : "url",
        },
        {
            "name" : "greencard.zip",
            "type" : "trojan",
            "media" : "zip",
        },
        {
            "name" : "credit_card.rar",
            "type" : "trojan",
            "media" : "zip",
        },    
        {
            "name" : "system35.dll",
            "type" : "virus",
            "media" : "exe",
        },  
        {
            "name" : "registry_mode.bat",
            "type" : "worm",
            "media" : "msi",
        }
    ]

    class Malware(Resource):
            def get (self, name):
                for malware in malwares:
                    if (name == malware["name"]):
                        return malware, 200
                return "Marlware not found", 404

            def post (self, name):
                parser = reqparse.RequestParser()
                parser.add_argument("type")
                parser.add_argument("media")
                args = parser.parse_args()

                for malware in malwares:
                    if(name == malware["name"]):
                        return"Malware with name {} already exits".format(name), 400
                malware = {
                    "name" : name,
                    "type" : args["type"],
                    "media" : args["media"]
                }

                malwares.append(malware)
                return malware, 201

            def put (self, name):
                parser = reqparse.RequestParser()
                parser.add_argument("type")
                parser.add_argument("media")
                args = parser.parse_args()

                for malware in malwares:
                    if (name==malware["name"]):
                        malware["type"] = args["type"]
                        malware["media"] = args["media"]
                        return malware, 200

                malware = {
                    "name" : name,
                    "type" : args["type"],
                    "media" : args["media"]
                }
        
                malwares.append(malware)
                return malware, 201

            def delete (self, name):
                global malwares
                malwares = [malware for malware in malwares if malware["name"] != name]
                return "{} is deleted.".format(name), 200
            
    api.add_resource(Malware, "/malware/<string:name>")
    app.run(debug = True) #enable flask to reload after a change, only develoing mode.

Con este curso me ha comenzado ha gustar php, qué es esto? :0
y con cada clase me gusta más. Se siente geniaaaaal

Eliminar datos a través de HTTP DELETE:
$ curl -X 'DELETE' http://localhost:8000/books/1

DELETE: Este método se utiliza para eliminar un registro existente, es similar a DELETE a la base de datos. No soporta el envío del payload.

  • GET optener recursos, tabnto colecciones como recursos puntulaes
  • POST crear recursos en tu servivod
  • PUT remplazo de recursos existentes por uno nuevo
  • Delete borra el recurso

Que sencillo es PHP cuando tienes conocimientos previos de programación.
me encanta

Vale, DELETE lo que hace es eliminar un recurso especificado.

Realmente no se suelen eliminar los recursos de una base de datos, una buena práctica es manejar estos datos con flags, en plan 1 es que está activo y 0 que está inactivo, y el método DELETE se encarga de poner en 0 las flags ^^

Fragmento de código en javascript:

app.delete('/books/:id', (req, res) => {
  const paramId = req.params.id
  // Verifica si se ha puesto un id y que este exista
  if(paramId && books[paramId]) {
    // Remueve el indice enviado y lo guarda en "deleted_book"
    const deleted_book = books.splice(paramId - 1, 1);

    // Envia un ok, el libro eliminado y la colección de libros actual
    res.send({ status: 'ok', deleted_book, books })
  } else {
    // En caso de no encontrar, devuelve error
    res.json({ status: 'Failed', error: 'missing or invalid param: id' });
  }
})

Y para eliminar solo es poner:
curl -X 'DELETE' localhost:5000/books/1 | jq, siendo el /books/1 el ID a eliminar.

Yo hice el mio en el framework de Lumen/PHP, espero seguir aprendiendo y que este aporte le sirva a alguien 😉 .

En el archivo routes/web.php :

<?php

/** @var \Laravel\Lumen\Routing\Router $router */

/*
|--------------------------------------------------------------------------
| Application Routes
|--------------------------------------------------------------------------
|
| Here is where you can register all of the routes for an application.
| It is a breeze. Simply tell Lumen the URIs it should respond to
| and give it the Closure to call when that URI is requested.
|
*/

//Definicion de las rutas para el API REST
$router->get('/{resource_type}', 'APIController@index');
$router->get('/{resource_type}/{resource_id}', 'APIController@index');
$router->post('/{resource_type}', 'APIController@index');
$router->put('/{resource_type}/{resource_id}', 'APIController@index');
$router->delete('/{resource_type}/{resource_id}', 'APIController@index');

Luego cree un controlador llamado app/Http/Controllers/APIController.php con el siguiente conteido:

<?php

namespace App\Http\Controllers;
use Illuminate\Http\Request;

class APIController extends Controller
{
    //Se define los tipos de recursos permitidos
    private $allowedResourceTypes = [
        'books',
        'authors',
        'genres',
    ];

    //se define los libros almacenados
    private $books = [
        1 => [
            'titulo' => 'Lo que el viento se llevo',
            'id_autor' => 2,
            'id_genero' => 2,
        ],
        2 => [
            'titulo' => 'La Iliada',
            'id_autor' => 1,
            'id_genero' => 1,
        ],
        3 => [
            'titulo' => 'La Odisea',
            'id_autor' => 1,
            'id_genero' => 1,
        ],
    ];

    //Se define la funcion principal que determinara que acción se realizara segun el metodo
    function index($resource_type, $resource_id = null, Request $request){
        //Si el tipo de recurso no es encontrado devolvera un mensaje de error y un estado de 404
        if(!in_array($resource_type, $this->allowedResourceTypes)){
            return response()->json([
                'error' => "resource type $resource_type is unknow"
            ], 404);
        }
        //Si el id del libro no es nulo y no existe en el arreglo de libros devolvera un mensaje de error y un estado de 404
        if(!is_null($resource_id)){
            if(!array_key_exists($resource_id, $this->books)){
                return response()->json([
                    'error' => "resource $resource_id doesn't exist"
                ], 404);
            }
        }
        //Se hace el analisis del metodo y se deriva la respuesta segun el metodo
        switch (strtoupper($request->method())) {
            case 'GET':
                return $this->get($resource_type, $resource_id, $request);
                break;
            case 'POST':
                return $this->post($resource_type, $request);
                break;
            case 'PUT':
                return $this->put($resource_type, $resource_id, $request);
                break;
            case 'DELETE':
                return $this->delete($resource_type, $resource_id, $request);
                break;
        }
    }

    //Metodo GET
    function get($resource_type, $resource_id, $request){
        //Si existe un id de recurso retornara solo ese elemento
        if(!is_null($resource_id)){
            return response()->json($this->books[$resource_id]);
        }
        //De lo contrario retornara todos los libros
        return response()->json($this->books);
    }
    //Metodo POST
    function post($resource_type, $request){
        //Lee todo el contenido de la peticion
        $new_book = $request->all();
        //La agraga al arreglo de libros
        $this->books[] = $new_book;
        //Retorna una respuesta de codigo 201 confirmando la creacion del elemento y todos los libros
        return response()->json([
            'message' => 'new element created',
            'books' => $this->books
        ], 201);
    }
    //Metodo PUT
    function put($resource_type, $resource_id, $request){
        //Lee todo el contenido de la peticion
        $update_book = $request->all();
        //Actualiza el elemento del arreglo de libros
        $this->books[$resource_id] = $update_book;
        //Retorna una respuesta de codigo 201 confirmando la actualizacion del elemento y todos los libros
        return response()->json([
            'message' => 'element updated',
            'books' => $this->books
        ], 201);
    }
    function delete($resource_type, $resource_id, $request){
        //Elimina el elemento del arreglo segun el id de recurso
        unset($this->books[$resource_id]);
        //Retorna una respuesta de codigo 200 confirmando la eliminacion del elemento y todos los libros
        return response()->json([
            'message' => 'element eliminated',
            'books' => $this->books
        ], 200);
        return "Adios";
    }
}
Listo, Ya se fue ese 'Odioso Libro' de mi Biblioteka de Libros. ![](https://static.platzi.com/media/user_upload/image-512fe5bf-9488-4d82-a1ad-d3b1daa87f5a.jpg) \nEsta Clase estuvo muy Buena junto colas anteriores tambien.

que bonito , solo falta el patch method, para modificar solo una parte de la entidad no toda como lo hace put

En Go:

func deleteBook(w http.ResponseWriter, r *http.Request, id int) {
	if id >= len(Books) {
		w.WriteHeader(http.StatusNotFound)
		fmt.Fprint(w, "<h1>Not Found</h1>")
		return
	}

	Books = append(Books[:id], Books[id+1:]...)
	w.WriteHeader(http.StatusOK)
	fmt.Fprint(w, "OK")

}

<code>


Mi código en python con FastAPI

El resultado del ejemplo.

este fue el menos complicado de crear 😃

en powershell de windows.

curl -Method DELETE http://localhost:8000/books/3

Con el DELETE borramos un elemento como tal completamente

interezante

¿por qué siempre se escriben en mayúsculas los verbos?

De nuevo, con el método DELETE se borra toda la colección del recurso.! No se puede borrar data puntual.

gracias 😃 me queda claro… php es más simple

El repositorio de la clase no funciona. ¿Podrian proporcionarmelo?

Hasta ahora me ha gustado mucho el curso, ya sabemos desplegar servicios REST, ahora veamos como hacerlo de forma segura

<?php 

function isJson( string $string ) : bool {
    json_decode($string);
    return (json_last_error() == JSON_ERROR_NONE);
}

//definiendo recursos
$books = [
    1 => [
        'titulo' => 'Lo que el viento se llevo',
        'id_autor' => 2,
        'id_genero' => 2,
    ],
    2 => [
        'titulo' => 'La Iliada',
        'id_autor' => 1,
        'id_genero' => 1,
    ],
    3 => [
        'titulo' => 'La Odisea',
        'id_autor' => 1,
        'id_genero' => 1,
    ],
];

//definimos recursos disponibles
$allowedResourceTypes = [
    'books',
    'authors',
    'genres'
];

$resourceType = array_key_exists( 'resource_type', $_GET ) ? $_GET['resource_type'] : '';
$resourceId = array_key_exists( 'resource_id', $_GET ) ? $_GET['resource_id'] : '';

//se valida la disponivilidad del curso
if ( !in_array( $resourceType, $allowedResourceTypes, true ) ) {
    die();
}

header( 'Content-Type: application/json' );

//se genera la respuesta
switch ( strtoupper( $_SERVER['REQUEST_METHOD'] ) ) {
    case 'GET':
        if ( !empty( $resourceType ) ) {
            if ( !empty( $resourceId ) && array_key_exists( $resourceId, $books ) ) {
                $json = json_encode( $books[$resourceId] );
                echo $json;

                break;
            }

            $json = json_encode( $books );
            echo $json;
        }

        break;
    case 'POST':
        $json = isJson( file_get_contents( 'php://input' ) ) ? json_decode( file_get_contents( 'php://input' ), true ) : '
        ';

        //validamos que la entrada sea un json
        if ( empty( $json ) ) {
            die();
        } 

        $books[] = $json;

        echo array_keys( $books )[count( $books ) - 1];
        // echo json_encode( $books );
        break;
    case 'PUT':
        //validamos que el recurso exista
        if ( !empty($resourceId) && array_key_exists( $resourceId, $books ) ) {
            $json = isJson( file_get_contents( 'php://input' ) ) ? json_decode( file_get_contents( 'php://input' ), true ) : '
            ';

            //validamos que la entrada sea un json
            if ( empty( $json ) ) {
                die();
            } 

            $books[$resourceId] = $json;

            // echo json_encode( $books );
            echo json_encode( $books[$resourceId] );
        }

        break;
    case 'DELETE':
        //validamos que el recurso exista
        if ( !empty($resourceId) && array_key_exists( $resourceId, $books ) ) {
            $books[$resourceId] = null;
            unset($books[$resourceId]);

            echo json_encode( $books );
        }
        break;
}

Excelente, reafirmando conocimientos…

Sentencia DELETE

GET: Obtener un recurso
POST: Crear un nuevo recurso
PUT: Modificar un recurso existente
DELETE: Borrar un recurso