From 9cde126e7c7fd40652a552771e215fbbbbecc59d Mon Sep 17 00:00:00 2001 From: Jorge Acosta <104621044+jacostaf10@users.noreply.github.com> Date: Wed, 5 Jul 2023 14:46:19 +0200 Subject: [PATCH] Add Spanish translation for basics/controllers and basics/errors (#847) Added Spanish translation for files `controllers` and `errors` located in the `basics` folder --------- Co-authored-by: Tim Condon <0xTim@users.noreply.github.com> --- docs/basics/controllers.es.md | 67 ++++++++++++ docs/basics/errors.es.md | 197 ++++++++++++++++++++++++++++++++++ 2 files changed, 264 insertions(+) create mode 100644 docs/basics/controllers.es.md create mode 100644 docs/basics/errors.es.md diff --git a/docs/basics/controllers.es.md b/docs/basics/controllers.es.md new file mode 100644 index 00000000..b36d39e5 --- /dev/null +++ b/docs/basics/controllers.es.md @@ -0,0 +1,67 @@ +# Controladores + +Los controladores son una gran manera de organizar tu código. Son colecciones de métodos que aceptan una petición (request) y devuleven una respuesta (response). + +Un buen sitio donde ubicar tus controladores sería en la carpeta [Controllers](../getting-started/folder-structure.es.md#controllers). + +## Descripción + +Veamos un controlador de ejemplo. + +```swift +import Vapor + +struct TodosController: RouteCollection { + func boot(routes: RoutesBuilder) throws { + let todos = routes.grouped("todos") + todos.get(use: index) + todos.post(use: create) + + todos.group(":id") { todo in + todo.get(use: show) + todo.put(use: update) + todo.delete(use: delete) + } + } + + func index(req: Request) async throws -> String { + // ... + } + + func create(req: Request) throws -> EventLoopFuture { + // ... + } + + func show(req: Request) throws -> String { + guard let id = req.parameters.get("id") else { + throw Abort(.internalServerError) + } + // ... + } + + func update(req: Request) throws -> String { + guard let id = req.parameters.get("id") else { + throw Abort(.internalServerError) + } + // ... + } + + func delete(req: Request) throws -> String { + guard let id = req.parameters.get("id") else { + throw Abort(.internalServerError) + } + // ... + } +} +``` + +Los métodos de un controlador deben aceptar siempre una `Request` (petición) y devolver algo `ResponseEncodable`. Este método puede ser síncrono o asíncrono (o devolver un `EventLoopFuture`). + +!!! note "Nota" + Un [EventLoopFuture](async.md) cuya expectativa es `ResponseEncodable` (por ejemplo, `EventLoopFuture`) es también `ResponseEncodable`. + +Finalmente necesitas registrar el controlador en `routes.swift`: + +```swift +try app.register(collection: TodosController()) +``` diff --git a/docs/basics/errors.es.md b/docs/basics/errors.es.md new file mode 100644 index 00000000..58b87246 --- /dev/null +++ b/docs/basics/errors.es.md @@ -0,0 +1,197 @@ +# Errores + +Vapor está basado en el protocolo `Error` de Swift para el manejo de errores. Los manejadores de rutas pueden lanzar (`throw`) un error o devolver un `EventLoopFuture` fallido. Lanzar o devolver un `Error` de Swift resultará en una respuesta de estado (status response) `500` y el error será registrado. `AbortError` y `DebuggableError` pueden usarse para cambiar la respuesta resultante y el registro respectivamente. El manejo de errores lo lleva a cabo `ErrorMiddleware`. Este middleware es añadido por defecto a la aplicación y puede reemplazarse por lógica personalizada si se desea. + +## Abort + +Vapor proporciona un struct de error por defecto llamado `Abort`. Este struct se conforma con ambos `AbortError` y `DebuggableError`. Puedes inicializarlo con un estado (status) HTTP y un motivo (reason) de fallo opcional. + +```swift +// Error 404, motivo (reason) por defecto "Not Found" usado. +throw Abort(.notFound) + +// Error 401,motivo (reason) personalizada usado. +throw Abort(.unauthorized, reason: "Invalid Credentials") +``` + +En situaciones asíncronas antiguas que no soportan lanzamiento de errores y en las que debes devolver un `EventLoopFuture`, como en un closure `flatMap`, puedes devolver un futuro fallido. + +```swift +guard let user = user else { + req.eventLoop.makeFailedFuture(Abort(.notFound)) +} +return user.save() +``` + +Vapor incluye una extensión de ayuda para hacer unwrapping de futuro con valores opcionales: `unwrap(or:)`. + +```swift +User.find(id, on: db) + .unwrap(or: Abort(.notFound)) + .flatMap +{ user in + // User no opcional proporcionado al closure. +} +``` + +Si `User.find` devuelve `nil`, el futuro fallará con el error suministrado. Sino, se suministrará el `flatMap` con un valor no opcional. Si usas `async`/`await` puedes manejar el opcional de la manera habitual: + +```swift +guard let user = try await User.find(id, on: db) { + throw Abort(.notFound) +} +``` + + +## Abort Error + +Por defecto, cualquier `Error` de Swift lanzado o devuelto por un closure de ruta resultará en una respuesta `500 Internal Server Error`. Cuando se compile en modo de depuración (debug mode), `ErrorMiddleware` incluirá una descripción del error. Esto se elimina cuando el proyecto es compilado en modo de despliegue (release mode) por razones de seguridad. + +Para configurar el estado (status) o motivo (reason) de la petición HTTP resultante para un error en específico, debes conformarlo a `AbortError`. + +```swift +import Vapor + +enum MyError { + case userNotLoggedIn + case invalidEmail(String) +} + +extension MyError: AbortError { + var reason: String { + switch self { + case .userNotLoggedIn: + return "User is not logged in." + case .invalidEmail(let email): + return "Email address is not valid: \(email)." + } + } + + var status: HTTPStatus { + switch self { + case .userNotLoggedIn: + return .unauthorized + case .invalidEmail: + return .badRequest + } + } +} +``` + +## Error Depurable + +`ErrorMiddleware` usa el método `Logger.report(error:)` para registrar errores lanzados por tus rutas. Este método comprobará la conformación a protocolos como `CustomStringConvertible` y `LocalizedError` para registrar mensajes legibles. + +Para personalizar el registro de errores, puedes conformar tus errores con `DebuggableError`. Este protocolo incluye una variedad de útiles propiedades como un identificador único, localización de fuentes (source location) y traza de la pila (stack trace). La mayoría de estas propiedades son opcionales, lo que facilita adoptar la conformancia. + +Para conformarse de mejor forma a `DebuggableError`, tu error debe ser un struct que permita guardar información sobre las trazas de fuente y pila en caso de ser necesario. Debajo hay un ejemplo del enum `MyError` mencionado anteriormente, actualizado para usar un `struct` y capturar información sobre la fuente de error. + +```swift +import Vapor + +struct MyError: DebuggableError { + enum Value { + case userNotLoggedIn + case invalidEmail(String) + } + + var identifier: String { + switch self.value { + case .userNotLoggedIn: + return "userNotLoggedIn" + case .invalidEmail: + return "invalidEmail" + } + } + + var reason: String { + switch self.value { + case .userNotLoggedIn: + return "User is not logged in." + case .invalidEmail(let email): + return "Email address is not valid: \(email)." + } + } + + var value: Value + var source: ErrorSource? + + init( + _ value: Value, + file: String = #file, + function: String = #function, + line: UInt = #line, + column: UInt = #column + ) { + self.value = value + self.source = .init( + file: file, + function: function, + line: line, + column: column + ) + } +} +``` + +`DebuggableError` tiene otras propiedades como `possibleCauses` y `suggestedFixes` que puedes usar para mejorar la depuración de tus errores. Echa un vistazo al protocolo para más información. + +## Stack Traces (Trazas de Pila) + +Vapor incluye soporte para visualizar stack traces para errores normales y crashes de Swift. + +### Swift Backtrace + +Vapor usa la librería de [SwiftBacktrace](https://github.com/swift-server/swift-backtrace) para proporcionar stack traces después de un error crítico (fatal error) o comprobaciones (assertion) en Linux. Para que esto funcione, tu app debe incluir símbolos de depuración (debug symbols) durante la compilación. + +```sh +swift build -c release -Xswiftc -g +``` + +### Trazas de Error + +Por defecto, `Abort` capturará el stack trace actual al inicializarse. Tus tipos de errores personalizados pueden conseguir esto conformándose con `DebuggableError` y guardando `StackTrace.capture()`. + +```swift +import Vapor + +struct MyError: DebuggableError { + var identifier: String + var reason: String + var stackTrace: StackTrace? + + init( + identifier: String, + reason: String, + stackTrace: StackTrace? = .capture() + ) { + self.identifier = identifier + self.reason = reason + self.stackTrace = stackTrace + } +} +``` + +Cuando el [nivel de registro](logging.es.md#nivel) de tu app se establece a `.debug` o inferior, stack traces de errores se incluirán en los registros. + +Los stack traces no serán capturados cuando el nivel de registro sea mayor que `.debug`. Para sobrescribir este comportamiento, establece `StackTrace.isCaptureEnabled` manualmente en `configure`. + +```swift +// Siempre captura stack traces, sin importar el nivel de registro. +StackTrace.isCaptureEnabled = true +``` + +## Middleware de Error + +`ErrorMiddleware` es el único middleware añadido a tu aplicación por defecto. Este middleware transforma errores de Swift que hayan sido lanzados o devueltos por tus controladores de rutas en respuestas HTTP. Sin este middleware, los errores lanzados darían lugar al cierre de la conexión sin una respuesta. + +Para personalizar el manejo de errores más allá de lo que `AbortError` y `DebuggableError` ofrecen, puedes reemplazar `ErrorMiddleware` con tu propia lógica de manejo de errores. Para hacerlo, elimina primero el middleware por defecto estableciendo una configuración vacía en `app.middleware`. Luego, añade tu propio middleware de manejo de errores como el primer middleware de tu aplicación. + +```swift +// Elimina todos los middleware existentes. +app.middleware = .init() +// Añade middleware de manejo de errores personalizado primero. +app.middleware.use(MyErrorMiddleware()) +``` + +Muy pocos middleware deberían ir _antes_ del middleware de manejo de errores. Una excepción a tener en cuenta de esta regla es `CORSMiddleware`.