mirror of https://github.com/vapor/docs.git
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>
This commit is contained in:
parent
0764d708ec
commit
9cde126e7c
|
|
@ -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<String> {
|
||||
// ...
|
||||
}
|
||||
|
||||
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<String>`) es también `ResponseEncodable`.
|
||||
|
||||
Finalmente necesitas registrar el controlador en `routes.swift`:
|
||||
|
||||
```swift
|
||||
try app.register(collection: TodosController())
|
||||
```
|
||||
|
|
@ -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`.
|
||||
Loading…
Reference in New Issue