Skip to content

Commit e766c66

Browse files
committed
Add Content, Controllers and Rounting translations for PT-BR
1 parent 7c71c73 commit e766c66

File tree

3 files changed

+789
-0
lines changed

3 files changed

+789
-0
lines changed

docs/basics/content.pt-BR.md

+282
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,282 @@
1+
# Conteúdo
2+
3+
A API de conteúdo do Vapor permite que você codifique/decodifique facilmente structs Codable para/de mensagens HTTP. A codificação [JSON](https://tools.ietf.org/html/rfc7159) é usada por padrão com suporte nativo para [Formulário Codificado por URL](https://pt.wikipedia.org/wiki/Codifica%C3%A7%C3%A3o_percentual#O_tipo_application/x-www-form-urlencoded) e [Multipart](https://tools.ietf.org/html/rfc2388). A API também é configurável, permitindo que você adicione, modifique ou substitua estratégias de codificação para determinados tipos de conteúdo HTTP.
4+
5+
## Visão Geral
6+
7+
Para entender como a API de conteúdo do Vapor funciona, você deve primeiro entender alguns conceitos básicos sobre mensagens HTTP. Dê uma olhada no exemplo de requisição a seguir.
8+
9+
```http
10+
POST /greeting HTTP/1.1
11+
content-type: application/json
12+
content-length: 18
13+
14+
{"hello": "world"}
15+
```
16+
17+
Esta requisição indica que contém dados codificados em JSON usando o cabeçalho `content-type` e o tipo de mídia `application/json`. Conforme prometido, alguns dados JSON seguem após os cabeçalhos no corpo.
18+
19+
### Struct de Conteúdo
20+
21+
O primeiro passo para decodificar esta mensagem HTTP é criar um tipo Codable que corresponda à estrutura esperada.
22+
23+
```swift
24+
struct Greeting: Content {
25+
var hello: String
26+
}
27+
```
28+
29+
Conformar o tipo a `Content` adicionará automaticamente conformidade a `Codable`, juntamente com utilitários adicionais para trabalhar com a API de conteúdo.
30+
31+
Uma vez que você tenha a estrutura de conteúdo, você pode decodificá-la da requisição recebida usando `req.content`.
32+
33+
```swift
34+
app.post("greeting") { req in
35+
let greeting = try req.content.decode(Greeting.self)
36+
print(greeting.hello) // "world"
37+
return HTTPStatus.ok
38+
}
39+
```
40+
41+
O método decode usa o tipo de conteúdo da requisição para encontrar um decodificador apropriado. Se nenhum decodificador for encontrado, ou se a requisição não contiver o cabeçalho de tipo de conteúdo, um erro `415` será lançado.
42+
43+
Isso significa que essa rota aceita automaticamente todos os outros tipos de conteúdo suportados, como formulário codificado por URL:
44+
45+
```http
46+
POST /greeting HTTP/1.1
47+
content-type: application/x-www-form-urlencoded
48+
content-length: 11
49+
50+
hello=world
51+
```
52+
53+
No caso de uploads de arquivos, sua propriedade de conteúdo deve ser do tipo `Data`.
54+
55+
```swift
56+
struct Profile: Content {
57+
var name: String
58+
var email: String
59+
var image: Data
60+
}
61+
```
62+
63+
### Tipos de Mídia Suportados
64+
65+
Abaixo estão os tipos de mídia que a API de conteúdo suporta por padrão.
66+
67+
| nome | valor do cabeçalho | tipo de mídia |
68+
|--------------------|------------------------------------|----------------------------|
69+
| JSON | application/json | `.json` |
70+
| Multipart | multipart/form-data | `.formData` |
71+
| Formulário Codificado por URL | application/x-www-form-urlencoded | `.urlEncodedForm` |
72+
| Texto simples | text/plain | `.plainText` |
73+
| HTML | text/html | `.html` |
74+
75+
Nem todos os tipos de mídia suportam todos os recursos de `Codable`. Por exemplo, JSON não suporta fragmentos de nível superior e Texto simples não suporta dados aninhados.
76+
77+
## Consulta
78+
79+
As APIs de Conteúdo do Vapor suportam o tratamento de dados codificados por URL na string de consulta da URL.
80+
81+
### Decodificação
82+
83+
Para entender como a decodificação de uma string de consulta URL funciona, dê uma olhada na requisição de exemplo a seguir.
84+
85+
```http
86+
GET /hello?name=Vapor HTTP/1.1
87+
content-length: 0
88+
```
89+
90+
Assim como as APIs para lidar com o conteúdo do corpo da mensagem HTTP, o primeiro passo para analisar strings de consulta URL é criar uma `struct` que corresponda à estrutura esperada.
91+
92+
```swift
93+
struct Hello: Content {
94+
var name: String?
95+
}
96+
```
97+
98+
Observe que `name` é uma `String` opcional, já que strings de consulta URL devem sempre ser opcionais. Se você quiser exigir um parâmetro, use um parâmetro de rota em vez disso.
99+
100+
Agora que você tem uma struct `Content` para a string de consulta esperada desta rota, você pode decodificá-la.
101+
102+
```swift
103+
app.get("hello") { req -> String in
104+
let hello = try req.query.decode(Hello.self)
105+
return "Hello, \(hello.name ?? "Anonymous")"
106+
}
107+
```
108+
109+
Esta rota resultaria na seguinte resposta, dada a requisição de exemplo acima:
110+
111+
```http
112+
HTTP/1.1 200 OK
113+
content-length: 12
114+
115+
Hello, Vapor
116+
```
117+
118+
Se a string de consulta fosse omitida, como na seguinte requisição, o nome "Anonymous" seria usado em vez disso.
119+
120+
```http
121+
GET /hello HTTP/1.1
122+
content-length: 0
123+
```
124+
125+
### Valor Único
126+
127+
Além de decodificar para uma struct `Content`, o Vapor também suporta a busca de valores únicos da string de consulta usando subscripts.
128+
129+
```swift
130+
let name: String? = req.query["name"]
131+
```
132+
133+
## Ganchos
134+
135+
O Vapor chamará automaticamente `beforeEncode` e `afterDecode` em um tipo `Content`. Implementações padrão são fornecidas que não fazem nada, mas você pode usar esses métodos para executar lógica personalizada.
136+
137+
```swift
138+
// Executa após este Content ser decodificado. `mutating` é necessário apenas para structs, não para classes.
139+
mutating func afterDecode() throws {
140+
// O nome pode não ser passado, mas se for, não pode ser uma string vazia.
141+
self.name = self.name?.trimmingCharacters(in: .whitespacesAndNewlines)
142+
if let name = self.name, name.isEmpty {
143+
throw Abort(.badRequest, reason: "Name must not be empty.")
144+
}
145+
}
146+
147+
// Executa antes deste Content ser codificado. `mutating` é necessário apenas para structs, não para classes.
148+
mutating func beforeEncode() throws {
149+
// Deve sempre passar um nome de volta, e ele não pode ser uma string vazia.
150+
guard
151+
let name = self.name?.trimmingCharacters(in: .whitespacesAndNewlines),
152+
!name.isEmpty
153+
else {
154+
throw Abort(.badRequest, reason: "Name must not be empty.")
155+
}
156+
self.name = name
157+
}
158+
```
159+
160+
## Substituir Padrões
161+
162+
Os codificadores e decodificadores padrão usados pelas APIs de Conteúdo do Vapor podem ser configurados.
163+
164+
### Global
165+
166+
`ContentConfiguration.global` permite que você altere os codificadores e decodificadores que o Vapor usa por padrão. Isso é útil para mudar como toda a sua aplicação analisa e serializa dados.
167+
168+
```swift
169+
// cria um novo codificador JSON que usa datas em formato de timestamp Unix
170+
let encoder = JSONEncoder()
171+
encoder.dateEncodingStrategy = .secondsSince1970
172+
173+
// substitui o codificador global usado para o tipo de mídia `.json`
174+
ContentConfiguration.global.use(encoder: encoder, for: .json)
175+
```
176+
177+
Modificar `ContentConfiguration` é geralmente feito em `configure.swift`.
178+
179+
### Uso Único
180+
181+
Chamadas para métodos de codificação e decodificação como `req.content.decode` suportam a passagem de codificadores personalizados para usos únicos.
182+
183+
```swift
184+
// cria um novo decodificador JSON que usa datas em formato de timestamp Unix
185+
let decoder = JSONDecoder()
186+
decoder.dateDecodingStrategy = .secondsSince1970
187+
188+
// decodifica a struct Hello usando um decodificador personalizado
189+
let hello = try req.content.decode(Hello.self, using: decoder)
190+
```
191+
192+
## Codificadores Personalizados
193+
194+
Aplicativos e pacotes de terceiros podem adicionar suporte para tipos de mídia que o Vapor não suporta por padrão, criando codificadores personalizados.
195+
196+
### Conteúdo
197+
198+
O Vapor especifica dois protocolos para codificadores capazes de lidar com conteúdo nos corpos de mensagens HTTP: `ContentDecoder` e `ContentEncoder`.
199+
200+
```swift
201+
public protocol ContentEncoder {
202+
func encode<E>(_ encodable: E, to body: inout ByteBuffer, headers: inout HTTPHeaders) throws
203+
where E: Encodable
204+
}
205+
206+
public protocol ContentDecoder {
207+
func decode<D>(_ decodable: D.Type, from body: ByteBuffer, headers: HTTPHeaders) throws -> D
208+
where D: Decodable
209+
}
210+
```
211+
212+
Conformar-se a esses protocolos permite que seus codificadores personalizados sejam registrados em `ContentConfiguration`, conforme especificado acima.
213+
214+
### Consulta de URL
215+
216+
O Vapor especifica dois protocolos para codificadores capazes de lidar com conteúdo em strings de consulta de URL: `URLQueryDecoder` e `URLQueryEncoder`.
217+
218+
```swift
219+
public protocol URLQueryDecoder {
220+
func decode<D>(_ decodable: D.Type, from url: URI) throws -> D
221+
where D: Decodable
222+
}
223+
224+
public protocol URLQueryEncoder {
225+
func encode<E>(_ encodable: E, to url: inout URI) throws
226+
where E: Encodable
227+
}
228+
```
229+
230+
Conformar-se a esses protocolos permite que seus codificadores personalizados sejam registrados em `ContentConfiguration` para lidar com strings de consulta de URL usando os métodos `use(urlEncoder:)` e `use(urlDecoder:)`.
231+
232+
### `ResponseEncodable` Personalizado
233+
234+
Outra abordagem envolve a implementação de `ResponseEncodable` em seus tipos. Considere este tipo de embrulho `HTML` trivial:
235+
236+
```swift
237+
struct HTML {
238+
let value: String
239+
}
240+
```
241+
242+
Em seguida, sua implementação `ResponseEncodable` seria assim:
243+
244+
```swift
245+
extension HTML: ResponseEncodable {
246+
public func encodeResponse(for request: Request) -> EventLoopFuture<Response> {
247+
var headers = HTTPHeaders()
248+
headers.add(name: .contentType, value: "text/html")
249+
return request.eventLoop.makeSucceededFuture(.init(
250+
status: .ok, headers: headers, body: .init(string: value)
251+
))
252+
}
253+
}
254+
```
255+
256+
Se estiver usando `async`/`await`, você pode usar `AsyncResponseEncodable`:
257+
258+
```swift
259+
extension HTML: AsyncResponseEncodable {
260+
public func encodeResponse(for request: Request) async throws -> Response {
261+
var headers = HTTPHeaders()
262+
headers.add(name: .contentType, value: "text/html")
263+
return .init(status: .ok, headers: headers, body: .init(string: value))
264+
}
265+
}
266+
```
267+
268+
Observe que isso permite personalizar o cabeçalho `Content-Type`. Consulte a [referência do HTTPHeaders](https://api.vapor.codes/vapor/documentation/vapor/response/headers) para mais detalhes.
269+
270+
Em seguida, você pode usar `HTML` como um tipo de resposta em suas rotas:
271+
272+
```swift
273+
app.get { _ in
274+
HTML(value: """
275+
<html>
276+
<body>
277+
<h1>Hello, World!</h1>
278+
</body>
279+
</html>
280+
""")
281+
}
282+
```

docs/basics/controllers.pt-BR.md

+70
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
# Controladores
2+
3+
Controladores são uma ótima maneira de organizar seu código. Eles são coleções de métodos que aceitam uma requisição e retornam uma resposta.
4+
5+
Um bom lugar para colocar seus controladores é na pasta [Controllers](../getting-started/folder-structure.md#controllers).
6+
7+
## Visão Geral
8+
9+
Vamos dar uma olhada em um exemplo de controlador.
10+
11+
```swift
12+
import Vapor
13+
14+
struct TodosController: RouteCollection {
15+
func boot(routes: RoutesBuilder) throws {
16+
let todos = routes.grouped("todos")
17+
todos.get(use: index)
18+
todos.post(use: create)
19+
20+
todos.group(":id") { todo in
21+
todo.get(use: show)
22+
todo.put(use: update)
23+
todo.delete(use: delete)
24+
}
25+
}
26+
27+
func index(req: Request) async throws -> [Todo] {
28+
try await Todo.query(on: req.db).all()
29+
}
30+
31+
func create(req: Request) async throws -> Todo {
32+
let todo = try req.content.decode(Todo.self)
33+
try await todo.save(on: req.db)
34+
return todo
35+
}
36+
37+
func show(req: Request) async throws -> Todo {
38+
guard let todo = try await Todo.find(req.parameters.get("id"), on: req.db) else {
39+
throw Abort(.notFound)
40+
}
41+
return todo
42+
}
43+
44+
func update(req: Request) async throws -> Todo {
45+
guard let todo = try await Todo.find(req.parameters.get("id"), on: req.db) else {
46+
throw Abort(.notFound)
47+
}
48+
let updatedTodo = try req.content.decode(Todo.self)
49+
todo.title = updatedTodo.title
50+
try await todo.save(on: req.db)
51+
return todo
52+
}
53+
54+
func delete(req: Request) async throws -> HTTPStatus {
55+
guard let todo = try await Todo.find(req.parameters.get("id"), on: req.db) else {
56+
throw Abort(.notFound)
57+
}
58+
try await todo.delete(on: req.db)
59+
return .ok
60+
}
61+
}
62+
```
63+
64+
Os métodos do controlador devem sempre aceitar uma `Request` e retornar algo que seja `ResponseEncodable`. Este método pode ser assíncrono ou síncrono.
65+
66+
Finalmente, você precisa registrar o controlador em `routes.swift`:
67+
68+
```swift
69+
try app.register(collection: TodosController())
70+
```

0 commit comments

Comments
 (0)