Pero esta vez quiero hacer las cosas bien, así que encontré de suerte a Colander (Con una documentación bastante útil hasta ahora) que es capaz de realizar algo como validar los datos JSON una vez llegan a nuestra aplicación. Y se integra bien con Pyramid. Y no hay ningún problema con los test, excepto escribirlos.
Añadimos colander como dependencia de nuestro proyecto en requires de ./ambiente/aplicacion/setup.py
(...) requires = [ 'pyramid', 'pyramid_debugtoolbar', 'waitress', 'nose', 'webtest', 'coverage', 'colander' ] (...)Lo instalamos
# Este sí, desde el directorio ./ambiente/aplicacion es la mejor idea python setup.py developCreamos un fichero ./ambiente/aplicacion/aplicacion/schemas/usuario.py el que creamos una clase que, descendiendo de algún tipo específico de Colander, sea capaz de definir la estructura de nuestro objeto JSON, aunque en realidad podemos hacer validaciones de cadenas simples y todo bien.
mkdir ./ambiente/aplicacion/aplicacion/schemas touch ./ambiente/aplicacion/aplicacion/schemas/__init__.pyY creamos el fichero ./ambiente/aplicacion/aplicacion/schemas/usuario.py con el siguiente contenido:
# coding: utf-8 import colander class Palabra(colander.SequenceSchema): # Palabra es un string utf-8 de al menos dos caracteres palabra = colander.SchemaNode(colander.String('utf-8'), validator=colander.Length(min=2)) class UsuarioEsquema(colander.MappingSchema): # nombre es un string utf-8 nombre = colander.SchemaNode(colander.String('utf-8')) # apellido es un string utf-8 apellido = colander.SchemaNode(colander.String('utf-8')) # palabras es una lista de palabras palabras = Palabra(validator=colander.Length(min=1)) if __name__ == '__main__': esquema = Data() data = {'nombre': 'Alexander', 'apellido': 'Ortíz', 'palabras': ['usuario', 'formidable']} data = {'nombre': 389, 'palabras': ['usuario', 'formidable']}Y en lo que ya parece una costumbre, actualizamos nuestra vista ./ambiente/aplicacion/aplicacion/views/actividades.py
# coding: utf-8 from pyramid.view import view_config from pyramid.httpexceptions import HTTPBadRequest from colander import Invalid from ..fichero_app.ficheros import Usuarios from ..schemas.usuario import UsuarioEsquema # Empieza el trabajo con la autenticación from pyramid.security import Allow, Deny, Everyone, NO_PERMISSION_REQUIRED, Authenticated # Dejamos por acá un esquema listo para usarse esquema = UsuarioEsquema() @view_config(route_name='ficheros_listado', renderer='json', permission='listar') def ficheros_listado(request): """Cuando request_method se configura acà, el mensaje es diferente porque la operación alcanzada es diferente The resource could not be found. predicate mismatch for view get_listar_ficheros (request_method = GET,HEAD) Por tanto lo mejor es configurarlo allá en __init__ """ ficheros = Usuarios() listado = ficheros.listado() return {'respuesta': listado} @view_config(route_name='ficheros_detalle', renderer='json', permission='detallar') def ficheros_detalle(request): usuario = request.matchdict['usuario'] ficheros = Usuarios() detalle = ficheros.detalle(usuario) return {'respuesta': detalle} @view_config(route_name='ficheros_creacion', renderer='json', permission='creacion') def ficheros_creacion(request): try: usuario = request.json_body['usuario'] data = esquema.deserialize(request.json_body['data']) except Invalid as e: return HTTPBadRequest(json_body=e.asdict()) except Exception as e: return HTTPBadRequest() ficheros = Usuarios() creacion = ficheros.creacion(usuario, data) return {'respuesta': creacion} @view_config(route_name='ficheros_modificacion', renderer='json', permission='modificacion') def ficheros_modificacion(request): usuario = request.matchdict['usuario'] try: data = esquema.deserialize(request.json_body['data']) except Invalid as e: return HTTPBadRequest(json_body=e.asdict()) except Exception as e: return HTTPBadRequest() ficheros = Usuarios() modificacion = ficheros.modificacion(usuario, data) return {'respuesta': modificacion} @view_config(route_name='ficheros_borrado', renderer='json', permission='borrado') def ficheros_borrado(request): usuario = request.matchdict['usuario'] ficheros = Usuarios() borrado = ficheros.borrado(usuario) return {'respuesta': borrado}Y para mantener las buenas costumbres, agregamos a Creacion un método test_ficheros_creacion_malformed en ./ambiente/aplicacion/aplicacion/tests/testFuncionales.py de la siguiente forma:
def test_ficheros_creacion_malformed(self): datos = {'usuario': 'fcornejo', 'data': {'nombre': 'Flor', 'apellido':'Cornejo', 'palabras': ['ente', 'obvio']}} # Dañamos el nombre, así nos aseguramos que sea ese contenido el equivocado datos['data']['nombre'] = 389 respuesta = self.testapp.post_json('/ficheros', status=400, params=datos) self.assertRegexpMatches(respuesta.json_body['nombre'], '389 is not a string')
No hay comentarios:
Publicar un comentario