A煤n no tienes acceso a esta clase

Crea una cuenta y contin煤a viendo este curso

Manejo de errores de un servicio REST

14/19
Recursos

De momento nuestra API no nos indica que haya ocurrido un error, solamente nos regresa un c贸digo 200 de HTTP que significa que la petici贸n se realiz贸 sin problemas.

Para mejorar nuestra API a帽adiremos respuestas con los c贸digos HTTP m谩s comunes:

  • 400 Bad Request: indica que el servidor no puede o no procesa la petici贸n debido a algo que es percibido como un error del cliente
  • 404 Not Found: el servidor no encuentra el recurso solicitado.
  • 500 Internal Server Error: la petici贸n no pudo procesarse por un error del servidor.

Aportes 36

Preguntas 4

Ordenar por:

驴Quieres ver m谩s aportes, preguntas y respuestas de la comunidad? Crea una cuenta o inicia sesi贸n.

Uno de los sitios que utilizo como referencia para los codigos http es httpstatuscode, recomendable 100%

Los c贸digos de estado en HTTP se clasifican en varios tipos:
1xx: Respuestas informativas
2xx: Peticiones correctas
3xx: Redirecciones
4xx: Errores del cliente
5xx: Errores del servidor
Los m谩s comunes:
400 Bad Request: Error en la petici贸n.
401 Unauthorized: Falta iniciar sesi贸n.
403 Forbidden: No se poseeen los permisos necesarios.
404 Not Found: No se ha podido encontrar el recurso.
500 Internal Server error: Usualmente fallo en la aplicaci贸n web.
502 Bad Gateway: Error entre la comunicaci贸n del servidor web y alguno de los servidores que act煤an de proxy.
503 Service Unavailable: Servidor est谩 caido por mantenimiento o est谩 sobrecargado.
504 Gateway Timeout: El servidor act煤a como puerta de enlace y no puede obtener una respuesta a tiempo.

En esta pagina puedes encontrar los codigos de error en forma de situaciones con gatos 馃惐
https://http.cat/

Codigo del cliente:

<?php
$ch = curl_init( $argv[1]);
curl_setopt(
	$ch,
	CURLOPT_RETURNTRANSFER,
	true
);

$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);

switch ($httpCode){
	case 200:
		echo 'Todo bien!';
		break;
	case 400:
		echo 'Pedido incorrecto';
		break;
	case 404:
		echo 'Recurso no encontrado';
		break;
	case 500:
		echo 'El servidor fallo';
		break;
}

Los c贸digos de error m谩s 煤tilizados en las API REST son:

200 OK (GET, POST, PUT):La solicitud ha tenido 茅xito.

201 Created (POST, PUT): La solicitud ha tenido 茅xito y se ha creado un nuevo recurso como resultado de ello.

301 Moved Permanently (GET, POST, PUT, PATH, DELETE): Este c贸digo de respuesta significa que la URI del recurso solicitado ha sido cambiado. Probablemente una nueva URI sea devuelta en la respuesta.

401 Unauthorized (GET, POST, PUT, PATH, DELETE): Es necesario autenticar para obtener la respuesta solicitada. Esta es similar a 403, pero en este caso, autenticaci贸n es posible.

404 Not Found (GET, POST, PUT, PATH, DELETE): El servidor no pudo encontrar el contenido solicitado. Este c贸digo de respuesta es uno de los m谩s famosos dada su alta ocurrencia en la web.

405 Method Not Allowed (GET, POST, PUT, PATH, DELETE): El m茅todo solicitado es conocido por el servidor pero ha sido deshabilitado y no puede ser utilizado.

500 Internal Server Error (GET, POST, PUT, PATH, DELETE): El servidor ha encontrado una situaci贸n que no sabe como manejarla.

M谩s sobre mensajes de error en: C贸digos de estado de respuesta HTTP

驴Que cojones es la imagen del ni帽o que sale en los primeros minutos?

esa imagen del chicle se ve muy asquerosa D:

Yo quisiera que Platzi subiera un curso de SOAP.

Solicito ayuda 馃槃 ----He perdido ya dos veces la evaluaci贸n por estas preguntas, ustedes me pueden aclarar estos temas la verdad aqu铆 no encuentro la respuesta

驴C贸mo debe informar el servidor acerca de errores ocurridos durante el procesamiento de un pedido?
Respuestas usadas / Cuerpo de la Respuesta - Excepciones

驴A trav茅s de qu茅 mecanismo se reciben errores al invocar a una API RESTful?
Respuestas usadas / Callbacks - Excepciones

C贸digos de estado 4XX
Indican que se ha producido un error cuyo responsable es el navegador:

400 (Bad Request), el servidor no es capaz de entender la petici贸n del navegador porque su sintaxis no es correcta.
401 (Unauthorized), el recurso solicitado por el navegador requiere de autenticaci贸n. La respuesta incluye una cabecera de tipo WWW-Authenticate para que el navegador pueda iniciar el proceso de autenticaci贸n.
402 (Payment Required), este c贸digo est谩 reservado para usos futuros.
403 (Forbidden), la petici贸n del navegador es correcta, pero el servidor no puede responder con el recurso solicitado porque se ha denegado el acceso.
404 (Not Found), el servidor no puede encontrar el recurso solicitado por el navegador y no es posible determinar si esta ausencia es temporal o permanente.
405 (Method Not Allowed), el navegador ha utilizado un m茅todo (GET, POST, etc.) no permitido por el servidor para obtener ese recurso.
406 (Not Acceptable), el recurso solicitado tiene un formato que en teor铆a no es aceptable por el navegador, seg煤n los valores que ha indicado en la cabecera Accept de la petici贸n.
407 (Proxy Authentication Required), es muy similar al c贸digo 401, pero en este caso, el navegador debe autenticarse primero con un proxy.
408 (Request Timeout), el navegador ha tardado demasiado tiempo en realizar su petici贸n y el servidor ya no espera esa petici贸n. No obstante, el navegador puede realizar nuevas peticiones cuando quiera.
409 (Conflict), la petici贸n del navegador no se ha podido completar porque se ha producido un conflicto con el recurso solicitado. El caso m谩s habitual es el de las peticiones de tipo PUT que intentan modificar un recurso que a su vez ya ha sido modificado por otro lado.
410 (Gone), no es posible encontrar el recurso solicitado por el navegador y esta ausencia se considera permanente. Si existe alguna posibilidad de que el recurso vuelva a estar disponible, se debe utilizar el c贸digo 404.
411 (Length Required), el servidor rechaza la petici贸n del navegador porque no incluye la cabecera Content-Length adecuada.
412 (Precondition Failed), el servidor no es capaz de cumplir con algunas de las condiciones impuestas por el navegador en su petici贸n.
413 (Request Entity Too Large), la petici贸n del navegador es demasiado grande y por ese motivo el servidor no la procesa.
414 (Request-URI Too Long), la URI de la petici贸n del navegador es demasiado grande y por ese motivo el servidor no la procesa (esta condici贸n se produce en muy raras ocasiones y casi siempre porque el navegador env铆a como GET una petici贸n que deber铆a ser POST).
415 (Unsupported Media Type), la petici贸n del navegador tiene un formato que no entiende el servidor y por eso no se procesa.
416 (Requested Range Not Satisfiable), el navegador ha solicitado una porci贸n inexistente de un recurso. Este error se produce cuando el navegador descarga por partes un archivo muy grande y calcula mal el tama帽o de alg煤n trozo.
417 (Expectation Failed), la petici贸n del navegador no se procesa porque el servidor no es capaz de cumplir con los requerimientos de la cabecera Expect de la petici贸n.
422 (Unprocessable Entity (WebDAV)), la petici贸n del navegador tiene el formato correcto, pero sus contenidos tienen alg煤n error sem谩ntico que impide al servidor responder.
423 (Locked (WebDAV)), el recurso solicitado por el navegador no se puede entregar porque est谩 bloqueado.
424 (Failed Dependency (WebDAV)), la petici贸n del navegador ha fallado debido al error de alguna petici贸n anterior (por ejemplo una petici贸n con el m茅todo PROPPATCH).
426 (Upgrade Required), el navegador debe cambiar a un protocolo diferente para realizar las peticiones (por ejemplo TLS/1.0).
428 (Precondition Required), el servidor requiere que la petici贸n del navegador sea condicional (este tipo de peticiones evitan los problemas producidos al modificar con PUT un recurso que ha sido modificado por otra parte).
429 (Too Many Requests), el navegador ha realizado demasiadas peticiones en un determinado per铆odo de tiempo (se utiliza sobre todo para forzar los l铆mites de consumo de recursos de las APIs).
431 (Request Header Fileds Too Large), el servidor no puede procesar la petici贸n porque una de las cabeceras de la petici贸n es demasiado grande. Este error tambi茅n se produce cuando la suma del tama帽o de todas las peticiones es demasiado grande.

Fuente: https://bit.ly/2oAlV6K

Estar铆a muy 煤til decir que para que funcione hay que quitar la parte de autenticaci贸n por tokens, sino siempre va a regresar un 200.

Mi c贸digo en javascript
Para este ejemplo cre茅 una ruta que obtenga el ID de un libro en espec铆fico y requiere autenticaci贸n. Para eso uso el Middleware de autenticaci贸n que ten铆a antes, el siguiente fragmento de c贸digo:

app.get('/books/:id', bookAuthenticator, (req, res) => {
  // Si no pasa la validaci贸n devuelve un 403 forbidden

  // Verificamos si el libro no existe
  if(!books[req.params.id]) {
    // Devolvemos un error 404 si no existe
    return res.status(404).json({ status: 'Not found' })
  } else {
    // Devolvemos el libro y estado 200 autom谩ticamente
    res.json(books[req.params.id])
  }
})

Para hacer m谩s f谩cil el ejemplo uso Postman que es una herramienta para consumir APIs


Caso 403 Forbidden. Consumir el API sin un m茅todo de autenticaci贸n


Caso 404 Not Found. Acceder a un libro inexistente


Caso 200 OK. Acceder a un libro existente y con autenticaci贸n

C贸digo en Python bas谩ndome en otros comentarios con mis apuntes y modificaciones:

# Imports
#from server_test.common.auth import SECRET_KEY
from flask import Flask, jsonify, make_response
from flask_restful import Resource, Api, abort, request
#from common.auth import token_requered
from functools import wraps
import jwt, datetime
import hmac, hashlib, time

#SECRET = 'Sh!! No se lo cuentes a nadie'


# Auth by Tokens
def token_requered(f):
    @wraps(f)
    def decorated(*args, **kwargs):
        token = request.headers.get('x-token') # get tokken by header
        #token = request.args.get("token")

        # There is not token
        if not token:
            return make_response(jsonify({'message': 'Token is missing!'}), 403)

        # Try to decode the token, it will raise error if it's incorrect
        try:
            data = jwt.decode(token, app.config['SECRET_KEY'], algorithms="HS256")
        except:
            return make_response(jsonify({'message': 'Token is invalid!'}), 403)

        return f(*args, **kwargs)

    return decorated

# Auth by HMAC
'''
def auth_required(func):
    def wrapper(self):
        try:
            hash_api = request.headers.get('X-HASH') # Get the headers
            hash_client = hmac.new(key=SECRET.encode(), digestmod=hashlib.sha1) # Set the hash algorithm
            hash_client.update(request.headers.get('X-UID').encode()) # Set the UID
            hash_client.update(request.headers.get('X-TIMESTAMP').encode()) # Set the TIMESTAMP (UNIX)
        
            # If hashes are the same, then give access to the function
            if hash_api == hash_client.hexdigest():
                return func(self)

        # An error occured trying to resolve the values necesarry for the hash
        except:
            return make_response('Please authenticate by HMAC on X headers!', 401, {'WWW-Autencticate': 'Basic reaml="Login Required"'})
        
        # Hashes are not a mach, return an error
        return make_response('Could not verify your login!', 401, {'WWW-Autencticate': 'Basic reaml="Login Required"'})

    return wrapper
'''

# Autentificaci贸n v铆a HTML
""" 
def auth_required(func):
    def wrapper(self):
        # print(request.authorization)

        # If the authentification is correct, then return the function that it wraps
        # If not, then return an error
        if request.authorization and request.authorization['username'] == 'carlos' and request.authorization['password'] == '1234':
            return func(self)
        return make_response('Could not verify your login!', 401, {'WWW-Autencticate': 'Basic reaml="Login Required"'})
    return wrapper
 """

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

app.config['SECRET_KEY'] = "TopSecret"

# 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):
    @token_requered
    def get(self):
        return jsonify({'data': BOOKS}) # Returns as json in data variables

    # Metodo para agregar nuevo libro
    @token_requered
    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):
    @token_requered
    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
    
    @token_requered
    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)

    @token_requered
    def delete(self, book_id):
        abort_if_book_doesnt_exits(book_id)
        del BOOKS[book_id]
        return jsonify(BOOKS)
        # return jsonify({'message':'successful delete'})

@app.route('/login')
def login():
    auth = request.authorization #username and password

    # Check the password for now
    if auth and auth.password == '1234':
        # Set the token, by username with expiration time and with the secret key
        token = jwt.encode({'user': auth.username, 'exp': datetime.datetime.utcnow() + datetime.timedelta(minutes=30)}, app.config['SECRET_KEY'])

        # Return the token to the client
        return jsonify({'token': token})

    # Error at verification
    return make_response('Could not verify!', 401, {'WWW-Authenticate': 'Basic realm="Login Requiered"'})

class Authors(Resource):
    pass

class Generes(Resource):
    pass

class Root(Resource):
    def get(self, resource_type):
        allowed_resource_types = [
            "books",
            "authors",
            "genres"
        ]
        if resource_type not in allowed_resource_types:
            abort(400, message="Error 404")

# 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')
api.add_resource(Root, '/<resource_type>')


if __name__ == '__main__':
    app.run(debug=True)
  • Curl_getinfo: obtener error en el cliente

  • http_response_code: informar errores del lado del server

Por alguna raz贸n me funciona solo si comento la validaci贸n de Token en server.php, de lo contrario cualquier consulta de recursos que no existen me sigue retornando 鈥淭odo bien!鈥 en la consola.

HTTP STATUS CODES

1脳脳 Informational

2脳脳 Success

3脳脳 Redirection

4脳脳 Client Error

5脳脳 Server Error

El mejor sitio para c贸digos HTTP Jaja:

https://httpstatusdogs.com/

Manejo de errores de un servicio REST

En una arquitectura REST tiene que ser factible que al ocurrir un error en las peticiones a un servidor, estas sean comunicadas al cliente, esto sirve para saber donde ha ocurrido el problema. Http tiene su lista errores cuando se utiliza este protocolo

Los c贸digos de estado en HTTP se clasifican en varios tipos:

  • 1xx: Respuestas informativas
  • 2xx: Peticiones correctas
  • 3xx: Redirecciones
  • 4xx: Errores del cliente
  • 5xx: Errores del servidor
  • Los m谩s comunes:
  • 400 Bad Request: Error en la petici贸n.
  • 401 Unauthorized: Falta iniciar sesi贸n.
  • 403 Forbidden: No se poseeen los permisos necesarios.
  • 404 Not Found: No se ha podido encontrar el recurso.
  • 500 Internal Server error: Usualmente fallo en la aplicaci贸n web.
  • 502 Bad Gateway: Error entre la comunicaci贸n del servidor web y alguno de los servidores que act煤an de proxy.
  • 503 Service Unavailable: Servidor est谩 caido por mantenimiento o est谩 sobrecargado.
  • 504 Gateway Timeout: El servidor act煤a como puerta de enlace y no puede obtener una respuesta a tiempo.

Para ver mas lista de errores
https://http.cat/
https://www.restapitutorial.com/httpstatuscodes.html

Caso de prueba

Para el caso prueba, se debe lo siguiente:

  • Del lado del servidor existe una funci贸n llamada http_response_code() sirve para Obtener o establecer el c贸digo de respuesta HTTP. Este se deber谩 configurar o colocar al momento que se ejecute una acci贸n en el servidor.
  • Del lado cliente.php se crea una estructura que se encarga de interpretar las respuesta del servidor y entregar una respuesta m谩s consisa

client.php

<?php

//  Se indica que la petici贸n viene por la terminal
$ch = curl_init($argv[1]);
// Se confifura curl para recibir la respuesta al
// ejecutar la petici贸n
curl_setopt(
    $ch,
    CURLOPT_RETURNTRANSFER,
    true
);

//Realiza la peteci贸n recibida por terminal
$response = curl_exec($ch);
// se optine la respuesta del servidor
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);

// estructura para interpretar las respuestas http
switch ($httpCode) {
    case 200:
        echo 'Todo bien!';
        break;
    case 400:
        echo 'Pedido incorrecto';
        break;
    case 404:
        echo 'Recurso no encontrado';
        break;
    case 500:
        echo 'El servidor fallo';
        break;
}

server.php

<?php

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

//Los recursos disponible, prueba
$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 los  tipos de recursos disponibles
$allowedResourceTypes = [
    'books',
    'authors',
    'genres',
];

// - Se obtiene de la url el valor resource_type,
// Luego verifica que el valor obtenido de
// resource_type se verifica que exista
//en  $allowedResourceType
$resourceType = $_GET['resource_type'];
if (!in_array($resourceType, $allowedResourceTypes)) {
    // Respuesta del servidor
    http_response_code(400);
    die;
}

// Se  verifica si en  el url que se est谩 enviando
// existe un id
$resourceId = array_key_exists('resource_id', $_GET) ? $_GET['resource_id'] : '';
$method = $_SERVER['REQUEST_METHOD'];

switch (strtoupper($method)) {

    case 'GET':
        if ("books" !== $resourceType) {
            // si pregunta por un recurso diferente a libro 404
            // como aun no se implemente entonces
            http_response_code(404);
            die;
        }
        if (!empty($resourceId)) {
            if (array_key_exists($resourceId, $books)) {
                //Existe el libro con el id indicado entonces
                echo json_encode(
                    $books[$resourceId]
                );
                http_response_code(200);
            } else{
                //S铆 el id  no est谩 asociado a ningun libro
                http_response_code(404);
            }
        } else {
            // Si no son ninguno de los anteriores caso entonces
            // se muestra toda la lista de libros
            echo json_encode(
                $books
            );
            http_response_code(200);
        }
        die;
        break;
    default:
        http_response_code(400);
        break;
}
<?php

/*
//-- Autenticacion via HTTP
//------------------------------->
$user = array_key_exists('PHP_AUTH_USER',$_SERVER) ? $_SERVER['PHP_AUTH_USER'] : '';
$pwd = array_key_exists('PHP_AUTH_PW',$_SERVER) ? $_SERVER['PHP_AUTH_PW'] : '';

if ($user !== 'mauro' || $pwd !== '1234') {
	die;
}
//-- Autenticacion via HTTP
//-------------------------------<
*/


/*
//-- Autenticacion via HMAC
//------------------------------->
if (!array_key_exists('HTTP_X_HASH',$_SERVER) || !array_key_exists('HTTP_X_TIMESTAMP',$_SERVER) || !array_key_exists('HTTP_X_UID',$_SERVER)) {
	die;
}

list($hash,$uid,$timestamp) = [
	$_SERVER['HTTP_X_HASH'],
	$_SERVER['HTTP_X_UID'],
	$_SERVER['HTTP_X_TIMESTAMP']
];

$secret = 'Sh!! No se lo cuentes a nadie!';

$newHash = sha1($uid.$timestamp.$secret);

if ($newHash !== $hash) {
	die;
}
// Autenticacion via HMAC
//-------------------------------<
*/



// Autenticaci贸n v铆a Access Tokens
//------------------------------->
if (!array_key_exists('HTTP_X_TOKEN',$_SERVER)) {
	http_response_code(401);
	die;
}
$url = 'http://localhost:8001';

$ch = curl_init($url);
curl_setopt(
	$ch,
	CURLOPT_HTTPHEADER,
	[
		"X-Token: {$_SERVER['HTTP_X_TOKEN']}"
	]
);
curl_setopt(
	$ch,
	CURLOPT_RETURNTRANSFER,
	true
);
$ret = curl_exec($ch);
if ($ret !== 'true'){
	http_response_code(403);
	die;
}
// Autenticaci贸n v铆a Access Tokens
//-------------------------------<


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

// Validamos que el recurso este disponible
$resourceType = $_GET['resource_type'];

if (!in_array($resourceType,$allowedResourceTypes)) {
	http_response_code(400);
	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
// utilizando un operador ternario
$resourceId = array_key_exists('resource_id', $_GET) ? $_GET['resource_id'] : '';

// Generamos la respuesta asumiendo que el pedido es correcto
switch (strtoupper($_SERVER['REQUEST_METHOD'])) {
	case 'GET':
		if (empty($resourceId)) {
			echo json_encode($books);
		} else {
			if (array_key_exists($resourceId,$books)) {
				echo json_encode($books[$resourceId]);
			} else {
				http_response_code(404);
			}
		}
		break;

	case 'POST':
		$json = file_get_contents('php://input');
		$books[] = json_decode($json,true);
		//echo array_keys($books)[count($books)-1];
		end($books);         // move the internal pointer to the end of the array
		$key = key($books);  // fetches the key of the element pointed to by the internal pointer
		echo json_encode($books[$key]);
 		break;

	case 'PUT':
		// Validamos que el recurso buscado exista
		if (!empty($resourceId) && array_key_exists($resourceId,$books)) {
			// Tomamos la entrada curda
			$json = file_get_contents('php://input');

			// Tansformamos el json recibido a un nuevo elemento
			$books[$resourceId] = json_decode($json,true);

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

	case 'DELETE':
		// Validamos que el recurso buscado exista
		if (!empty($resourceId) && array_key_exists($resourceId,$books)) {
			unset($books[$resourceId]);
			echo json_encode($books);
		}
		break;
}



// Inicio el servidor en la terminal 1
// 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

como par茅ntesis, creo que la foto de un ni帽o con la cara desfigurada no aporta en nada, es mas es chocante.

Les dejo el c贸digo del cliente con comentarios y con una modificaci贸n para poder realizar la petici贸n a trav茅s de 茅l con la autenticaci贸n por Tokens de Acceso (el token se pasa como segundo argumento despues de la URL al ejecutar el cliente)

<?php
    // Preparamos la llamada CURL con el primer argumento pasado por
    // consola al ejecutar el cliente.
    $ch = curl_init($argv[1]);
    // Guardamos el Token de autenticaci贸n que ser谩 el segundo argumento
    // pasado por consola al ejecutar el cliente
    $token = array_key_exists(2, $argv) ? $argv[2] : '';
    // Agregamos una opci贸n a la llamada CURL con el Token de autenticaci贸n
    curl_setopt($ch, CURLOPT_HTTPHEADER, ["X_Token: {$token}"]);
    // Agregamos la opci枚n de retorno
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    // Ejecutamos la llamada CURL
    $response = curl_exec($ch);
    // Obtenemos el codigo que devuelve el servidor a la nuestra petici贸n
    $http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
    // Manejamos los codigos HTTP
    switch($http_code){
        case 200:
            echo 'Todo Bien'.PHP_EOL;
            echo $response.PHP_EOL;
            break;
        case 400:
            echo 'Pedido incorrecto'.PHP_EOL;
            break;
        case 401:
            echo 'Fallo de autenticaci贸n'.PHP_EOL;
            break;
        case 404:
            echo 'Recurso no encontrado'.PHP_EOL;
            break;
        case 500:
            echo 'El servidor fall贸'.PHP_EOL;
            break;
    }
?>

Buenas compa帽eros, tengo un problema, a la hora de tirar el comando de php client.php http://localhost:8000/bo me sigue diciendo 鈥楾odo bien鈥. No se si es que no tengo iniciados los servidores necesarios, tengo en de 鈥榬outer.php鈥 y el de 鈥榓uth_server.php鈥.

Os dejo por aqui el repositorio para que le hecheis un ojo al codigo y a ver si alguno me sabe decir por que me ocurre.
https://github.com/alessandrostfr/Apirest1

Para mejorar nuestra API a帽adiremos respuestas con los c贸digos HTTP m谩s comunes:

  • 400 Bad Request: indica que el servidor no puede o no procesa la petici贸n debido a algo que es percibido como un error del cliente
  • 404 Not Found: el servidor no encuentra el recurso solicitado.
  • 500 Internal Server Error: la petici贸n no pudo procesarse por un error del servidor.

Esto es algo que muchas API鈥檚 deben de hacer, siempre hay que emitir un c贸digo de estado al realizar cualquier acci贸n para informar cuando todo sale bien o algo falla, y los clientes tambi茅n deben tener validaciones para todos estos casos ^^

Manejo de errores de un servicio REST


De momento nuestra API no nos indica que haya ocurrido un error, solamente nos regresa un c贸digo 200 de HTTP que significa que la petici贸n se realiz贸 sin problemas.

Exelente

Excelente el control de errores desde al lado del cliente como desde el lado del servidor.

Es recomendable aparte de devolver un error 404 devolver el campo o parte del request que est谩 mal? Si es as铆, cual seria la estructura del objeto json recomendada?
{
errores: [ 鈥淓l id es un campo requerido鈥, 鈥淓l campo nombre no debe exceder los 10 caracteres鈥漖
}

se deben manejar los errores 馃槂

El servidor informa de los errores a trav茅s de los c贸digos de error.

HTTP cats para que tengan una referencia de los codigos de estado con gatos馃槀

Tambi茅n podemos crear nuestros propios c贸digos de error cuando se quiere dar detalle en alg煤n evento inesperado.

Excelente鈥

<h3>Manejo de errores de un servicio REST</h3>

Es importante crear c贸digos de error para que el cliente sepa porque su petici贸n no tuvo respuesta del servidor.

C贸digos de error

<?php

$ch = curl_init( $argv[1] );
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);

switch ($httpCode) {
    case 200:
        echo 'Todo bien!';
        break;

    case 400:
        echo 'Pedido incorrecto';
        break;

    case 500:
        echo 'El servidor fall贸';
        break;

    default:
        // h
        break;
}

La funci贸n http_response_code( ) nos deja poner el mensaje de error que responde http.

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

Para mas contexto.
https://httpstatusdogs.com/