python - restful - tutorial api rest flask
Flask API RESTful puntos finales mĂșltiples y complejos (1)
Estás cometiendo dos errores.
En primer lugar, Flask-RESTful te lleva a pensar que un recurso se implementa con una sola URL. En realidad, puede tener muchas URL diferentes que devuelven recursos del mismo tipo. En Flask-RESTful, tendrá que crear una subclase de Resource
diferente para cada URL, pero conceptualmente esas URL pertenecen al mismo recurso. Tenga en cuenta que, de hecho, ha creado dos instancias por recurso ya para manejar la lista y las solicitudes individuales.
El segundo error que estás cometiendo es que esperas que el cliente conozca todas las URL en tu API. Esta no es una buena forma de crear API, lo ideal es que el cliente solo conozca algunas URL de nivel superior y luego descubra el resto de los datos en las respuestas de los de nivel superior.
En su API, puede exponer los /api/users
y /api/cities
como API de nivel superior. Las URL a ciudades y usuarios individuales se incluirán en las respuestas. Por ejemplo, si invoco http://example.com/api/users
para obtener la lista de usuarios, puedo obtener esta respuesta:
{
"users": [
{
"url": "http://example.com/api/user/1",
"name": "John Smith",
"city": "http://example.com/api/city/35"
},
{
"url": "http://example.com/api/user/2",
"name": "Susan Jones",
"city": "http://example.com/api/city/2"
}
]
}
Tenga en cuenta que la representación JSON de un usuario incluye la URL de ese usuario y también la URL de la ciudad. El cliente no necesita saber cómo construirlos, porque se los dan.
Obteniendo ciudades por su nombre
La URL de una ciudad es /api/city/<id>
, y la URL para obtener la lista completa de ciudades es /api/cities
, tal como lo tiene definido.
Si también necesita buscar ciudades por su nombre, puede ampliar el punto final de "ciudades" para hacer eso. Por ejemplo, podría tener URLs en la forma /api/cities/<name>
devolver la lista de ciudades que coinciden con el término de búsqueda dado como <name>
.
Con Flask-RESTful, tendrá que definir una nueva subclase de Resource
para eso, por ejemplo:
class CitiesByNameAPI(Resource):
def __init__(self):
# ...
def get(self, name):
# ...
api.add_resource(CitiesByNameAPI, ''/api/cities/<name>'', endpoint = ''cities_by_name'')
Obtener todos los usuarios que pertenecen a una ciudad
Cuando el cliente solicita una ciudad, debe obtener una respuesta que incluya una URL para obtener los usuarios en esa ciudad. Por ejemplo, supongamos que a partir de la respuesta /api/users
anterior deseo conocer la ciudad del primer usuario. Así que ahora envío una solicitud a http://example/api/city/35
, y recibo la siguiente respuesta JSON:
{
"url": "http://example.com/api/city/35",
"name": "San Francisco",
"users": "http://example/com/api/city/35/users"
}
Ahora tengo la ciudad, y eso me dio una URL que puedo usar para obtener todos los usuarios en esa ciudad.
Tenga en cuenta que no importa que sus URL sean feas o difíciles de construir, porque el cliente nunca necesita construir la mayoría de ellas desde cero, sino que las obtiene del servidor. Esto también le permite cambiar el formato de las URL en el futuro.
Para implementar la URL que obtiene los usuarios por ciudad, agrega otra subclase de Resource
:
class UsersByCityAPI(Resource):
def __init__(self):
# ...
def get(self, id):
# ...
api.add_resource(UsersByCityAPI, ''/api/cities/<int:id>/users'', endpoint = ''users_by_city'')
¡Espero que esto ayude!
En mi API Flask-RESTful, imagina que tengo dos objetos, usuarios y ciudades. Es una relación de 1 a muchos. Ahora cuando creo mi API y le agrego recursos, todo lo que puedo hacer es asignarles URL muy fáciles y generales. Aquí está el código (con cosas inútiles no incluidas):
class UserAPI(Resource): #The API class that handles a single user
def __init__(self):
#Initialize
def get(self, id):
#GET requests
def put(self, id):
#PUT requests
def delete(self, id):
#DELETE requests
class UserListAPI(Resource): #The API class that handles the whole group of Users
def __init__(self):
def get(self):
def post(self):
api.add_resource(UserAPI, ''/api/user/<int:id>'', endpoint = ''user'')
api.add_resource(UserListAPI, ''/api/users/'', endpoint = ''users'')
class CityAPI(Resource):
def __init__(self):
def get(self, id):
def put(self, id):
def delete(self, id):
class CityListAPI(Resource):
def __init__(self):
def get(self):
def post(self):
api.add_resource(CityListAPI, ''/api/cities/'', endpoint = ''cities'')
api.add_resource(CityAPI, ''/api/city/<int:id>'', endpoint = ''city'')
Como puede ver, puedo hacer todo lo que quiero para implementar una funcionalidad muy básica. Puedo obtener, publicar, poner y eliminar ambos objetos. Sin embargo, mi objetivo es doble:
(1) Para poder solicitar con otros parámetros como el nombre de la ciudad en lugar de solo la identificación de la ciudad. Se vería algo así como:
api.add_resource(CityAPI, ''/api/city/<string:name>'', endpoint = ''city'')
excepto que no me arrojaría este error:
AssertionError: la asignación de función de vista sobrescribe una función de punto final existente
(2) Para poder combinar los dos recursos en una solicitud. Supongamos que quería obtener todos los usuarios asociados con alguna ciudad. En las URL REST, debería verse algo así como:
/api/cities/<int:id>/users
¿Cómo hago eso con Flask? ¿Qué punto final lo mapeo?
Básicamente, estoy buscando maneras de llevar mi API de básica a usable. Gracias por cualquier idea / consejo