Este proyect está basado en el playground DIP-Final del repositorio Solid-Samples
La intención de este proyecto es:
-
Conocer URLSession y su implementación con diferentes herramientas.
-
Usar las mejores prácticas de codificación y decodificación de datos JSON.
-
Mostrar las mejores prácticas de manejo de errores de API.
-
Crea una enumeración
NetworkingClientErrors
para manejar los siguientes errores del cliente:- Error al crear una URL inválida a partir de un endpoint.
- Error al decodificar los datos de una respuesta.
-
Crea una enumeración
NetworkingServerErrors
para manejar los siguientes errores del servidor:- Error interno del servidor 500.
- Error de datos no encontrados.
-
Elimina la estructura
DataNotFoundError
y reemplázala por el caso correspondiente deNetworkingServerErrors
.
NOTA: Define los mensajes de error de todos estos casos en inglés usando LocalizedError
.
-
Crea un protocolo
Endpoint
que defina las características genéricas de un endpoint como su path, queries y url base. -
Modifica
URLRequestFactory
renombrando su función actual por:func make() throws -> URLRequest
-
Utiliza herencia de protocolos para que
Endpoint
herede deURLRequestFactory
. -
Crea una extensión de
Endpoint
y escribe una implementación default para la función heredada deURLRequestFactory
. Utiliza el error correspondiente deNetworkingClientErrors
en caso de no poder obtener unaURL
válida. -
Actualiza
URLSessionFetcher
para usar la nueva abstracción deURLRequestFactory
y manejar sus errores. -
Elimina
DogsURLRequestFactory
yCatsURLRequestFactory
.
-
Declara la URL base del servidor:
let animalsAPIBaseURL = URL(string: "https://baz-example.free.beeceptor.com")!
. -
Crea una implementación de
Endpoint
para obtener una lista de gatitos desde:/v2/cats
-
Reemplaza el
LocalFileFetcher
enCatsUIComposer
por unURLSessionFetcher
con tu nuevo request alEndpoint
de cats. -
Arregla el threading utilizando el patron
Decorator
para crear unMainThreadFetcherDecorator
.
-
Crea una implementación de
Endpoint
para consumir una lista de perritos:/v2/dogs
-
El DogsService requiere la implementación de
async/await
para funcionar, por lo tanto:- Crea un nuevo protocolo
AsyncFetcher
que maneje requests conasync/await. Copia la función declarada en
Fetchery utiliza la función
Refactor / Convert Function to Asyncde
Xcodepara ayudarte a crear la función con
async/await`. - Crea una extension de
URLSessionFetcher
que conforme conAsyncFetcher
y crea un wrapper deasync/await
. Utiliza la funciónRefactor / Add Async Wrapper
de Xcode para ayudarte a crear la función deasync/await
.
- Crea un nuevo protocolo
-
Inyecta un
AsyncFetcher
enDogsService
y reemplaza la data mock en el método por una llamada a fetcher. -
Agrega
keyDecodingStrategy
al modeloDog
para renombrar las propiedades de:snake_case
a:lowerCammelCase
.
NOTA: En esta implementación no fue necesario crear un Decorator
para manejar la ejecución en el Main Queue, ¿por qué?
-
Modifica la clase
URLSessionFetcher
para manejar los errores de respuesta del servidor. -
Maneja los errores en
CatsServiceImp
y enDogsServiceImp
, para evitar que los errores que se definieron en la capa de red sean visibles para el usuario final. No olvides que puedes implementar el protocoloLocalizedError
para proveer mensajes personalizados en ellocalizedDescription
del error. -
Crea una enumeración llamada
DogsErrors
con los siguientes errores personalizados:- Cuando el array de perritos está vacío: “No encontramos perritos en este momento.”
- Cuando el servidor responde 500: “El servidor de perritos está fuera de servicio. Inténtalo más tarde.”
- En otro caso: “Ocurrió un error desconocido mientras buscábamos perritos :(”
-
Crea una enumeración llamada
CatsErrors
con los siguientes errores personalizados:- Cuando el array de gatitos está vacío: “No encontramos gatitos en este momento.”
- Cuando el servidor responde 500: “El servidor de gatitos está fuera de servicio. Inténtalo más tarde.”
- En otro caso: “Ocurrió un error desconocido mientras buscábamos gatitos :(”
GET /v2/dogs
Mock status as 200
GET /v2/cats
Mock status as 200
Declara implementaciones de los siguientes endpoints para simular llamadas vacías o con error del servidor y reemplázalas temporalmente donde sea necesarios para simular errores en tus UIViewControllers
.
Puedes usar los siguientes endpoints para simular las respuestas vacías del servidor:
GET /v2/cats/empty
Mock status as 200
GET /v2/dogs/empty
Mock status as 200
Puedes usar los siguientes endpoints para simular respuestas de error del servidor:
GET /v2/cats/error
Mock status as 500
GET /v2/dogs/error
Mock status as 500
- Los cambios en la capa de Networking no deberían obligarte a modificar tus vistas.
- Puedes extender la funcionalidad de tus clases de Networking para atender las necesidades específicas de tus vistas, como en el caso de
async/await
. - Tanto los datos de las vistas como sus mensajes de error, pueden desarrollarse incluso si los endpoints aún no están listos.
- Todos estos beneficios los obtuvimos gracias la aplicación de los principios SOLID.
- El threading también es una responsabilidad que regularmente delegamos a las vistas. Al usar el patrón Decorator podemos delegar esta responsabilidad.
- Usando
async/await
facilita mucho programar código asíncrono. La respuesta al por qué no es necesario manejar los updates en el main queue la puedes encontrar aquí: Using the MainActor attribute to automatically dispatch UI updates on the main queue - Probar todos estos cambios requiere que compilemos la aplicación y hagamos llamadas realeas a las APIs.