Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
76 changes: 76 additions & 0 deletions docs/basics/client.ko.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
# 클라이언트(Client)

Vapor의 클라이언트는 외부 리소스에 HTTP 요청을 보낼 수 있습니다. 클라이언트는 [async-http-client](https://github.com/swift-server/async-http-client)을 기반으로 만들어졌으며, [content](content.md) API로 통합되어 있습니다.

## 개요

`Application`을 통해 기본 클라이언트에 접근할 수 있습니다. 또는, 라우터 핸들러 안에서 `Request`를 통해 접근할 수 있습니다.

```swift
app.client // Client

app.get("test") { req in
req.client // Client
}
```

애플리케이션의 클라이언트는 설정(Configuration)을 하는 동안에 HTTP 요청을 만드는데 유용합니다. 만약 라우터 핸들러 안에서 HTTP 요청을 만든다면, 항상 request의 클라이언트를 사용하세요.

### 메서드(Methods)

원하는 URL을 `GET` 메서드에 전달해서 `GET` 요청을 만들어보세요.

```swift
let response = try await req.client.get("https://httpbin.org/status/200")
```

`get`, `post`, 그리고 `delete` 같은 각각의 HTTP 메서드를 위한 메서드들이 있습니다. 클라이언트의 응답은 HTTP 상태 코드, 헤더, 본문을 포함하고, Future 형태로 반환됩니다.

### 컨텐츠(Content)

클라이언트의 요청과 응답에서 데이터를 처리하는 데 Vapor의 [content](content.md) API를 사용할 수 있습니다. 컨텐츠를 인코딩하거나, 쿼리 파라미터나 헤더를 요청에 추가하기 위해서는 `beforeSend` 클로저를 사용하세요.

```swift
let response = try await req.client.post("https://httpbin.org/status/200") { req in
// Encode query string to the request URL.
try req.query.encode(["q": "test"])

// Encode JSON to the request body.
try req.content.encode(["hello": "world"])

// Add auth header to the request
let auth = BasicAuthorization(username: "something", password: "somethingelse")
req.headers.basicAuthorization = auth
}
// Handle the response.
```

비슷한 방식으로, `Content`를 사용해서 응답 본문을 디코딩 할 수 있습니다.

```swift
let response = try await req.client.get("https://httpbin.org/json")
let json = try response.content.decode(MyJSONResponse.self)
```

만약 future을 사용한다면, `flatMapThrowing`을 사용할 수 있습니다.

```swift
return req.client.get("https://httpbin.org/json").flatMapThrowing { res in
try res.content.decode(MyJSONResponse.self)
}.flatMap { json in
// Use JSON here
}
```

## 설정(Configuration)

애플리케이션을 통해 내부 HTTP 클라이언트를 설정할 수 있습니다.

```swift
// Disable automatic redirect following.
app.http.client.configuration.redirectConfiguration = .disallow
```

기본 클라이언트는 반드시 처음 _사용하기 전에_ 먼저 설정을 해야 합니다.


70 changes: 70 additions & 0 deletions docs/basics/controllers.ko.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
# 컨트롤러(Controllers)

컨트롤러는 코드를 그룹화하는데 좋은 방법입니다. 컨트롤러는 요청(request)을 받고 응답(response)을 반환하는 메서드들의 모음입니다.

컨트롤러가 위치하기에 좋은 곳은 [Controllers](../getting-started/folder-structure.md#controllers) 폴더입니다.

## 개요

예시 컨트롤러를 살펴보겠습니다.

```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 -> [Todo] {
try await Todo.query(on: req.db).all()
}

func create(req: Request) async throws -> Todo {
let todo = try req.content.decode(Todo.self)
try await todo.save(on: req.db)
return todo
}

func show(req: Request) async throws -> Todo {
guard let todo = try await Todo.find(req.parameters.get("id"), on: req.db) else {
throw Abort(.notFound)
}
return todo
}

func update(req: Request) async throws -> Todo {
guard let todo = try await Todo.find(req.parameters.get("id"), on: req.db) else {
throw Abort(.notFound)
}
let updatedTodo = try req.content.decode(Todo.self)
todo.title = updatedTodo.title
try await todo.save(on: req.db)
return todo
}

func delete(req: Request) async throws -> HTTPStatus {
guard let todo = try await Todo.find(req.parameters.get("id"), on: req.db) else {
throw Abort(.notFound)
}
try await todo.delete(on: req.db)
return .ok
}
}
```

컨트롤러 메서드는 `Request`을 받고 `ResponseEncodable` 을 준수하는 응답을 반환해야 합니다. 동기 또는 비동기 방식 모두 가능합니다.

마지막으로 `routes.swift`에서 컨트롤러를 등록해야 합니다.

```swift
try app.register(collection: TodosController())
```
144 changes: 144 additions & 0 deletions docs/basics/environment.ko.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
# 환경설정(Environment)

Vapor의 환경설정 API는 앱을 동적으로 설정할 수 있도록 합니다. 앱은 기본적으로 `development` 환경을 사용합니다. `production`이나 `staging` 같은 유용한 다른 환경을 정의할 수 있고, 각 케이스마다 다르게 설정할 수 있습니다. 필요에 따라 프로세스의 환경이나 `.env` 파일의 변수들을 사용할 수 있습니다.

`app.environment`를 사용해서 현재 환경설정에 접근할 수 있습니다. `configure(_:)` 메서드 안에서 이 프로퍼티와 스위치를 사용하면 환경에 따라 다르게 설정할 수 있습니다.

```swift
switch app.environment {
case .production:
app.databases.use(....)
default:
app.databases.use(...)
}
```

## 환경설정 변경하기

기본으로 앱은 `development` 모드로 실행됩니다. 앱을 부팅할 때, `--env` (`-e`) 플래그를 전달해서 환경설정을 변경할 수 있습니다.

```swift
swift run App serve --env production
```

Vapor는 다음과 같은 환경이 있습니다.

|name|short|description|
|-|-|-|
|production|prod|사용자들에게 제공하기 위한 환경입니다|
|development|dev|로컬 개발을 위한 환경입니다.|
|testing|test|유닛 테스트를 위한 환경입니다.|

!!! info
특별한 설정이 없다면 `production` 환경은 기본으로 `notice` 레벨로 로그를 기록합니다. 다른 환경들은 기본으로 `info` 레벨입니다.

`--env` (`-e`) 플래그에 전체 또는 축약 이름을 전달해서 설정할 수 있습니다.

```swift
swift run App serve -e prod
```

## 프로세스 변수(Process Variables)

`Environment`는 프로세스의 환경 변수들에 접근할 수 있도록 간단한 문자열 기반의 API를 제공합니다.

```swift
let foo = Environment.get("FOO")
print(foo) // String?
```

`get` 이외에도, `Environment`는 `process`를 통한 동적 멤버 조회 API도 제공합니다.

```swift
let foo = Environment.process.FOO
print(foo) // String?
```

터미널에서 앱을 실행하는 경우에는 `export`를 사용해서 환경 변수를 설정할 수 있습니다.

```sh
export FOO=BAR
swift run App serve
```

Xcode에서 앱을 실행하는 경우에는 `App` Scheme을 수정해서 환경 변수를 설정할 수 있습니다

## .env (dotenv) 파일

Dotenv 파일은 환경 변수를 자동으로 저장하기 위해서 Key-Value 형태의 리스트를 사용합니다. 이 파일은 수동으로 환경 변수를 설정할 필요가 없어서 쉽게 사용할 수 있습니다.

Vapor는 현재 작업 디렉토리에서 dotenv 파일을 검색합니다. 만약 Xcode를 사용한다면 `App` Scheme에서 작업 디렉토리를 지정해 줄 필요가 있습니다.

프로젝트 루트 폴더에 위치한 env 파일에 다음과 같은 내용이 있다고 가정하겠습니다.

```sh
FOO=BAR
```

어플리케이션이 부팅될 때, 다른 프로세스 환경 변수처럼 파일의 컨텐츠에 접근할 수 있습니다.

```swift
let foo = Environment.get("FOO")
print(foo) // String?
```

!!! info
이미 프로세스 환경설정에 존재하는 변수들은 `.env` 파일에 명시되었더라도 재설정되지 않습니다.

Vapor는 `.env` 파일에 외에도 현재 환경을 위한 dotenv 파일을 로드하려고 합니다. 예를 들어 `development` 환경에서는 Vapor는 `.env.development` 파일을 로드할 것입니다. 특정 환경의 `.env` 파일 안의 값들은 일반 `.env` 파일보다 우선시 됩니다.

기본 값으로 구성된 템플릿으로서 `.env` 파일을 프로젝트에 포함하는 것은 일반적인 방식입니다. 특정 환경 파일은 `.gitignore`에서 다음 패턴을 사용해서 업로드되지 않도록 합니다.

```gitignore
.env.*
```

새로운 컴퓨터에 프로젝트를 클론(clone) 할 때, `.env` 템플릿 파일은 복사되고 올바른 값들을 입력할 수 있습니다.

```sh
cp .env .env.development
vim .env.development
```

!!! warning
패스워드 같은 민감한 정보의 dotenv 파일들은 버전 관리에 절대로 커밋(commit) 되지 않도록 하세요.

만약 dotfile를 로드하는데 어려움이 있다면, 더 많은 정보를 위해서 `--log debug` 플래그를 사용해서 디버그 로깅을 시도해 보세요.

## 커스텀 환경설정

`Environment`을 확장해서 커스텀 환경설정 이름을 정의할 수 있습니다.

```swift
extension Environment {
static var staging: Environment {
.custom(name: "staging")
}
}
```

어플리케이션의 환경설정은 보통 `entrypoint.swift`에서 `Environment.detect()`를 사용해서 설정합니다.

```swift
@main
enum Entrypoint {
static func main() async throws {
var env = try Environment.detect()
try LoggingSystem.bootstrap(from: &env)

let app = Application(env)
defer { app.shutdown() }

try await configure(app)
try await app.runFromAsyncMainEntrypoint()
}
}
```

`detect` 메서드는 프로세스의 명령 줄 인자와 `--env` 플래그를 자동으로 사용합니다. 커스텀 `Environment` 구조체를 초기화하는 작업으로 이를 재설정할 수 있습니다.

```swift
let env = Environment(name: "testing", arguments: ["vapor"])
```

arguments 배열에는 최소한 하나의 실행 가능한 이름을 나타내는 인자를 포함해야 합니다. 명령 줄에 인자를 제공하는 것 같은 시뮬레이션을 하기 위해서, 추가적인 인자들을 제공할 수 있습니다. 특히 테스트를 위해서 사용할 때 유용합니다.
Loading