No tienes acceso a esta clase

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

Modificar datos a través de HTTP PUT

9/19
Recursos

Es importante recordar que el método PUT hace un reemplazo, no modificaciones puntuales. Por ello la información que enviemos a través de la petición debe ser completa.

Aportes 30

Preguntas 9

Ordenar por:

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

Código de la clase, Método PUT

<?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':
        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}'
?>

PATCH

HTTP PUT method only allows a complete replacement of a document. A PATCH request on the other hand, is used to make changes to part of the resource at a location. That is, it PATCHES the resource — changing its properties. It is used to make minor updates to resources and it’s not required to be idempotent.

GET
El método GET solicita una representación de un recurso específico. Las peticiones que usan el método GET sólo deben recuperar datos.
HEAD
El método HEAD pide una respuesta idéntica a la de una petición GET, pero sin el cuerpo de la respuesta.
POST
El método POST se utiliza para enviar una entidad a un recurso en específico, causando a menudo un cambio en el estado o efectos secundarios en el servidor.
PUT
El modo PUT reemplaza todas las representaciones actuales del recurso de destino con la carga útil de la petición.

DELETE
El método DELETE borra un recurso en específico.
CONNECT
El método CONNECT establece un túnel hacia el servidor identificado por el recurso.

OPTIONS
El método OPTIONS es utilizado para describir las opciones de comunicación para el recurso de destino.
TRACE
El método TRACE realiza una prueba de bucle de retorno de mensaje a lo largo de la ruta al recurso de destino.

PATCH
El método PATCH es utilizado para aplicar modificaciones parciales a un recurso.

Vale, PUT hace un reemplazo COMPLETO del recurso, si queremos hacer modificaciones puntuales debemos usar el método PATCH (Recomiendo investigarlo)

Apuntes:
La modificación de datos correspondería a un update en un CRUD, y tiene partes similares a las de GET y POST.
Nota: Para los que usan IIS, deben dirigirse a la herramienta de “asignaciones de controlador”, hacer doble click en el controlador de PHP (para el caso que tengan instalados mas de 2 interpretes, seleccionen el que les aparezca en el phpinfo), dirigirse a la opción de restricciones de solicitudes, luego en la pestaña de los versos, seleccionar “todos los verbos”. IIS por defecto nos presenta problemas con los verbos PUT y DELETE.

Mi version en Python basándome en el código de demás usuarios de clases previas:

# Imports
from flask import Flask, jsonify, make_response
from flask_restful import Resource, Api, abort, request

# Create app and api
app = Flask(__name__)
api = Api(app)

# Data base
BOOKS = {
    '1': {
        'isbn': '744586',
        'title': 'Cien años de soledad',
        'description': 'Lorem insup lol.',
        'autor': 'Gabriel Garcia Marquez'
    },
    '2': {
        'isbn': '7894546',
        'title': 'De animales a dioses',
        'description': 'Lorem insup lol.',
        'autor': 'Yuval Noah Harari'
    }
}

# Aborts the request and returns an error
def abort_if_book_doesnt_exits(book_id):
    if book_id not in BOOKS:
        abort(404, message='El libro con id {} no existe'.format(book_id))

# Returns the whole book list
class BookList(Resource):
    def get(self):
        return jsonify({'data': BOOKS}) # Returns as json in data variables

    # Metodo para agregar nuevo libro
    def post(self):
        # Getting the request as json format
        json = request.get_json(force=True)

        # Index to post the new book
        index = len(BOOKS) + 1

        # Putting the new book in the database
        BOOKS.update( {'{}'.format(index): json } )

        # Returining the ID to the user
        return 'Libro agregado correctamente con ID: ' + str(index)

# Returns an especific id book
class Book(Resource):
    def get(self, book_id):
            abort_if_book_doesnt_exits(book_id)
            return make_response( jsonify(BOOKS[book_id]), 200 ) # Returns a response as json with some info code

    def put(self, book_id):
        # Getting the request as json format
        json = request.get_json(force=True)

        # If the id donesn't exist, then quit
        abort_if_book_doesnt_exits(book_id)

        # Replace the information of the book
        BOOKS.update( {'{}'.format(book_id): json} )

        # Return the whole collection
        return jsonify(BOOKS)

class Authors(Resource):
    pass

class Generes(Resource):
    pass

# Add resources as REST arquitecture
api.add_resource(BookList, '/books')
api.add_resource(Book, '/books/<book_id>') #<> means it's a variable
api.add_resource(Authors, '/authors')
api.add_resource(Generes, '/generes')

if __name__ == '__main__':
    app.run(debug=True)

El método PUT hace reemplazos, la información se debe de enviar completa.
Petición:
$ curl -X 'PUT' http://localhost:8000/books/1 -d '{"titulo": "Nuevo Libro", "id_autor": 1, "id_genero": 2}'

El metodo PUT reemplaza toda la información completa del recurso, pero existe también el metodo PATCH que puede reemplazar datos específicos, como por ejemplo solo el nombre, o solo el autor

GET para obtener un recurso del servidor del servidor
POST para actualizar un recurso del servidor
PUT para crear un recurso del servidor
DELETE para eliminar un recurso del servidor

Pesimo curso, le netflix

Fragmento de código en javascript con los ejemplos que pase en las clases anteriores:

app.put('/books/:id', (req, res) => {
  const paramId = req.params.id
  // Verifica si se ha puesto un id y que este exista
  if(paramId && books[paramId]) {
    const book = books[paramId];

    // Modificar solo los datos que se hayan enviado
    book.title = req.body.title || book.title;
    book.id_author = req.body.id_author || book.id_author;
    book.id_genre = req.body.id_genre || book.id_genre;
    // Esta sintaxis dice: 
    // "Es igual al dato enviado (req.body.title), 
    // Y si está vacío (||) dejar el valor por defecto (book.title)"

    // Guardar el libro modificado
    books[paramId] = book;

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

De esta forma podemos enviar solo el dato que queremos modificar, o enviar los 3 datos.

curl --header "Content-Type: application/json" -X 'PUT' localhost:5000/books/2 -d '{"title": "Libro modificado" }' | jq

Fijate que pongo /books/2, ya que NodeJS nos permite esta función de forma nativa. Recibiendo /books/:id como req.params.id

Se ve mucho más complejo que PHP, pero en realidad lo he hecho complejo para hacer una validación simple, y no pueda alterar la estructura que ya teníamos.

aqui les dejo el codigo en python y con flask

Con un poco de lectura en el codigo, se comprende mejor.

curl -i -X PUT-H "Content-Type: application/json" -d "{""titulo"":""EL LOBO DE WALL STREET"",""id_autor"":5,""id_genero"":6}" http://localhost/api_rest/route.php/books/1

Para los que no le esta funcionando el comando de curl en windows, yo uso la terminal de laragon.

λ curl -H "Content-Type:application/json" -X PUT -d "{ \"titulo\":\"Iliadaaaa\",\"id_autor\": 1,\"genero\": 2}" http://localhost:8000/books/1```

Si les sigue marcando errores o mas bien no les muestra nada les dire como consejo que empiecen a debuggear, es una excelente practica para entender lo que se esta haciendo

Todo bien pero en mi caso debo iniciar el servidor para que lo cambios sean efectuados

### ¿Por qué existe `PATCH` en REST? La razón de tener ambos métodos es que, en algunos casos, quieres evitar sobrecargar la comunicación enviando datos innecesarios. `PATCH` es más ligero porque solo envías los datos que cambian, lo que puede ser muy eficiente en aplicaciones con grandes recursos o estructuras de datos. Esto también minimiza el riesgo de sobrescribir campos no deseados.
`PATCH` **(Actualización parcial)** * Se utiliza cuando deseas **modificar solo algunos campos** de un recurso existente, sin afectar el resto de los campos. * Es ideal para actualizaciones **parciales**. En lugar de enviar todos los datos del recurso, envías solo los campos que quieres modificar. * Es una operación más eficiente cuando necesitas cambiar solo algunas propiedades del recursos

bien explicado

Con Go:

package main

import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"
	"strconv"
)

var AllowedResources = map[string]bool{
	"books":   true,
	"authors": true,
	"genres":  true,
}

type Book struct {
	Titulo    string `json:"titulo"`
	Id_Autor  int    `json:"id_autor"`
	Id_gereno int    `json:"id_gereno"`
}

var Books = []Book{
	{
		Titulo:    "Lo que el viento se llevo",
		Id_Autor:  2,
		Id_gereno: 2,
	},
	{
		Titulo:    "El señor de los anillos",
		Id_Autor:  1,
		Id_gereno: 1,
	},
	{
		Titulo:    "La Odisea",
		Id_Autor:  1,
		Id_gereno: 3,
	},
}

func main() {
	http.Handle("/", http.HandlerFunc(ExampleHandler))
	http.HandleFunc("/books", books)
	http.HandleFunc("/book/", book)

	http.ListenAndServe(":8080", nil)
}

func book(w http.ResponseWriter, r *http.Request) {
	idstr := r.URL.Path[len("/book/"):]
	id, err := strconv.Atoi(idstr)
	if err != nil {
		w.WriteHeader(http.StatusBadRequest)
		fmt.Fprint(w, "<h1>Bad Request</h1>")
		return
	}

	switch r.Method {
	case http.MethodGet:
		getBook(w, r, id)
	case http.MethodPut:
		putBook(w, r, id)
	case http.MethodDelete:
		w.Write([]byte("DELETE"))
	}
}

func getBook(w http.ResponseWriter, r *http.Request, id int) {
	// Get a single book
	maxBooks := len(Books)

	if id >= maxBooks {
		w.WriteHeader(http.StatusNotFound)
		fmt.Fprint(w, "<h1>Not Found</h1>")
		return
	}

	book := Books[id]
	response, err := json.Marshal(book)
	if err != nil {
		w.WriteHeader(http.StatusInternalServerError)
		fmt.Fprint(w, "<h1>Internal Server Error</h1>")
		return
	}

	fmt.Fprint(w, string(response))
}

func putBook(w http.ResponseWriter, r *http.Request, id int) {
	var book Book

	body, err := ioutil.ReadAll(r.Body)
	if err != nil {
		w.WriteHeader(http.StatusBadRequest)
		fmt.Fprint(w, "<h1>Bad Request</h1>")
		return
	}

	if err := json.Unmarshal(body, &book); err != nil {
		w.WriteHeader(http.StatusBadRequest)
		fmt.Fprint(w, "<h1>Bad Request</h1>")
		return
	}

	if id >= len(Books) {
		w.WriteHeader(http.StatusNotFound)
		fmt.Fprint(w, "<h1>Not Found</h1>")
		return
	}

	Books[id] = book
	w.WriteHeader(http.StatusOK)
	fmt.Fprint(w, "OK")
}

func books(w http.ResponseWriter, r *http.Request) {
	switch r.Method {
	case "GET":
		getBooks(w, r)
	case "POST":
		postBooks(w, r)
	}
}

func getBooks(w http.ResponseWriter, r *http.Request) {
	respose, err := json.Marshal(Books)
	if err != nil {
		w.WriteHeader(http.StatusInternalServerError)
		fmt.Fprint(w, "<h1>Internal Server Error</h1>")
		return
	}

	w.Header().Set("Content-Type", "application/json")
	fmt.Fprint(w, string(respose))
}

func postBooks(w http.ResponseWriter, r *http.Request) {
	var book Book

	body, err := ioutil.ReadAll(r.Body)
	if err != nil {
		w.WriteHeader(http.StatusBadRequest)
		fmt.Fprint(w, "<h1>Bad Request</h1>")
		return
	}

	if err := json.Unmarshal(body, &book); err != nil {
		fmt.Println(err)
		w.WriteHeader(http.StatusBadRequest)
		fmt.Fprint(w, "<h1>Bad Request, error on unmarshal</h1>")
		return
	}

	Books = append(Books, book)
	w.WriteHeader(http.StatusCreated)
	fmt.Fprint(w, len(Books)-1)
}

Mi código en Python con FastAPI

Algo importante que dijo el profesor es que el método PUT debemos enviar todos los campos. Si queremos modificar sólo un campo utilizamos el método PATCH. Saludos

Código de ejercicio.

Metodo put remplaza toda la informacion, no funcina como una actualizacion espesifica de un dato.

Excelente información
Cuando se usa PUT la actualización de la información debe de ser completa, se debe de enviar todos los datos

Excelente clase.! Haciendo una analogía con CRUD en base de datos, el método PUT no permite modificar un campo, se actualiza toda el registro, es por ello que la información debe estar completa

Que tal a todos, sigo los pasos del teacher, pero cuando ejecuto el código no me aparece el json que cambiamos, es más no aparece nada, ayuda

Excelente