This commit is contained in:
Yoichiro Tanaka 2025-06-19 09:38:38 +09:00 committed by GitHub
commit 92dac516d1
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
40 changed files with 382 additions and 284 deletions

View File

@ -86,7 +86,7 @@ app.queues.add(emailJob)
新しいキューワーカーを開始するには、`swift run App queues` を実行します。特定の種類のワーカーを実行する場合は、`swift run App queues --queue emails` と指定することもできます。
!!! tip
ワーカーは本番環境で実行し続ける必要があります。長時間実行するプロセスを維持する方法については、ホスティングプロバイダーに従ってください。例えば、Heroku では、Procfile に `worker: Run queues` のように "worker" dyno を指定できます。これを設定すると、ダッシュボードのリソースタブや `heroku ps:scale worker=1`(または任意の dyno 数)でワーカーを開始できます。
ワーカーは本番環境で実行し続ける必要があります。長時間実行するプロセスを維持する方法については、ホスティングプロバイダーに相談してください。例えば、Heroku では、Procfile に `worker: Run queues` のように "worker" dyno を指定できます。これを設定すると、ダッシュボードのリソースタブや `heroku ps:scale worker=1`(または任意の dyno 数)でワーカーを開始できます。
### プロセス内でワーカーを実行 {#running-workers-in-process}
@ -103,7 +103,7 @@ try app.queues.startScheduledJobs()
```
!!! warning
キューワーカーをコマンドラインまたはプロセス内ワーカー経由で起動しない場合、ジョブはディスパッチされません。
キューワーカーをコマンドラインまたはプロセス内ワーカー経由で起動しない、ジョブはディスパッチされません。
## `Job` プロトコル {#the-job-protocol}
@ -156,7 +156,7 @@ struct EmailJob: AsyncJob {
`Payload` 型が `Codable` プロトコルを実装していることを確認してください。
!!! tip
**Getting Started** の指示に従って、このジョブを設定ファイルに追加することを忘れないでください。
**はじめに** の指示に従って、このジョブを設定ファイルに追加することを忘れないでください。
## ジョブのディスパッチ {#dispatching-jobs}
@ -242,7 +242,7 @@ app.get("email") { req async throws -> String in
}
```
ジョブが `delay` パラメータの前にデキューされた場合、ドライバによってジョブが再キューされます。
ジョブが遅延パラメータの前にデキューされた場合、ドライバによってジョブが再キューされます。
### 優先度の指定 {#specify-a-priority}
@ -308,7 +308,7 @@ struct SendEmailCommand: AsyncCommand {
キューを指定しない場合、ジョブは `default` キューで実行されます。各キュータイプのワーカーを起動する手順については、**Getting Started** の指示に従ってください。
キューを指定しない場合、ジョブは `default` キューで実行されます。各キュータイプのワーカーを起動する手順については、**はじめに** の指示に従ってください。
## ジョブのスケジューリング {#scheduling-jobs}
@ -325,7 +325,7 @@ swift run App queues --scheduled
```
!!! tip
ワーカーは本番環境で実行し続ける必要があります。長時間実行するプロセスを維持する方法については、ホスティングプロバイダーに従ってください。例えば、Heroku では、Procfile に `worker: App queues --scheduled` と指定することで「worker」 dyno を指定できます。
ワーカーは本番環境で実行し続ける必要があります。長時間実行するプロセスを維持する方法については、ホスティングプロバイダーに相談してください。例えば、Heroku では、Procfile に `worker: App queues --scheduled` と指定することで「worker」 dyno を指定できます。
### `ScheduledJob` の作成 {#creating-a-scheduledjob}
@ -447,3 +447,28 @@ app.queues.add(MyEventDelegate())
- [QueuesDatabaseHooks](https://github.com/vapor-community/queues-database-hooks)
- [QueuesDash](https://github.com/gotranseo/queues-dash)
## テスト {#testing}
同期の問題を避け、決定論的なテストを確保するために、Queues パッケージは `XCTQueue` ライブラリとテスト専用の `AsyncTestQueuesDriver` ドライバーを提供しており、次のように使用できます:
```swift
final class UserCreationServiceTests: XCTestCase {
var app: Application!
override func setUp() async throws {
self.app = try await Application.make(.testing)
try await configure(app)
// テスト用のドライバーをオーバーライド
app.queues.use(.asyncTest)
}
override func tearDown() async throws {
try await self.app.asyncShutdown()
self.app = nil
}
}
```
詳細については、[Romain Pouclet のブログ記事](https://romain.codes/2024/10/08/using-and-testing-vapor-queues/)を参照してください。

View File

@ -66,7 +66,7 @@ app.http.server.configuration.backlog = 128
app.http.server.configuration.reuseAddress = false
```
### TCP No Delay {#tcp-no-delay}
### TCP No Delay
`tcpNoDelay`パラメーターを有効にすると、TCPパケットの遅延を最小限に抑えようとします。デフォルトは`true`です。
@ -132,7 +132,7 @@ app.http.server.configuration.supportPipelining = true
app.http.server.configuration.supportVersions = [.two]
```
### TLS {#tls}
### TLS
`tlsConfiguration`パラメーターは、サーバーでTLSSSLが有効かどうかを制御します。デフォルトは`nil`です。

View File

@ -51,7 +51,7 @@ app.sessions.use(.memory)
本番環境での使用例については、データベースを使用してアプリの複数のインスタンス間でセッションを永続化および共有する他のセッションドライバーを確認してください。
### Fluent {#fluent}
### Fluent
Fluentには、アプリケーションのデータベースにセッションデータを保存するサポートが含まれています。このセクションでは、[Fluentを設定](../fluent/overview.md)し、データベースに接続できることを前提としています。最初のステップは、Fluentセッションドライバーを有効にすることです。
@ -75,7 +75,7 @@ app.migrations.add(SessionRecord.migration)
新しいマイグレーションを追加した後、必ずアプリケーションのマイグレーションを実行してください。セッションはアプリケーションのデータベースに保存されるようになり、再起動間で永続化され、アプリの複数のインスタンス間で共有できます。
### Redis {#redis}
### Redis
Redisは、設定されたRedisインスタンスにセッションデータを保存するサポートを提供します。このセクションでは、[Redisを設定](../redis/overview.md)し、Redisインスタンスにコマンドを送信できることを前提としています。

View File

@ -1,6 +1,6 @@
# テスト {#testing}
## VaporTesting {#vaportesting}
## VaporTesting
Vaporには`VaporTesting`というモジュールが含まれており、`Swift Testing`をベースとしたテストヘルパーを提供しています。これらのテストヘルパーを使用すると、Vaporアプリケーションにプログラムでテストリクエストを送信したり、HTTPサーバー経由で実行したりできます。
@ -162,7 +162,7 @@ private func withApp(_ test: (Application) async throws -> ()) async throws {
}
```
## XCTVapor {#xctvapor}
## XCTVapor
Vaporには`XCTVapor`というモジュールが含まれており、`XCTest`をベースとしたテストヘルパーを提供しています。これらのテストヘルパーを使用すると、Vaporアプリケーションにプログラムでテストリクエストを送信したり、HTTPサーバー経由で実行したりできます。

View File

@ -6,7 +6,7 @@ Vaporのトレーシング APIは[swift-distributed-tracing](https://github.com/
Swiftでのトレーシングとスパンに馴染みがない場合は、[OpenTelemetryトレースドキュメント](https://opentelemetry.io/ja/docs/concepts/signals/traces/)と[swift-distributed-tracingドキュメント](https://swiftpackageindex.com/apple/swift-distributed-tracing/main/documentation/tracing)を確認してください。
## TracingMiddleware {#tracingmiddleware}
## TracingMiddleware
各リクエストに対して完全に注釈付きのスパンを自動的に作成するには、アプリケーションに`TracingMiddleware`を追加します。

View File

@ -1,4 +1,4 @@
# 非同期
# 非同期 {#async}
## Async Await
@ -8,7 +8,7 @@ Vaporは、低レベルの非同期プログラミングのためのプリミテ
VaporのAPIの多くは、`EventLoopFuture`と`async`/`await`の両方のバージョンを提供するようになり、どちらが最適かを選択できるようになりました。一般的には、1つのルートハンドラーにつき1つのプログラミングモデルのみを使用し、コードの中で混在させないようにすべきです。イベントループを明示的に制御する必要があるアプリケーションや、非常に高性能が求められるアプリケーションについては、カスタムエグゼキュータが実装されるまで`EventLoopFuture`を使用し続けるべきです。それ以外の人々には、読みやすさや保守性の利点が小さなパフォーマンスのペナルティをはるかに上回るため、`async`/`await`を使用すべきです。
### async/awaitへの移行
### async/awaitへの移行 {#migrating-to-asyncawait}
async/awaitに移行するにはいくつかのステップが必要です。まず、macOSを使用している場合は、macOS 12 Monterey以降とXcode 13.1以降が必要です。他のプラットフォームでは、Swift 5.5以降を実行している必要があります。次に、すべての依存関係を更新したことを確認してください。
@ -71,7 +71,7 @@ routes.get("firstUser") { req async throws -> String in
}
```
### 古い API と新しい API の使用
### 古い API と新しい API の使用 {#working-with-old-and-new-apis}
まだ `async`/`await` バージョンを提供していない API に遭遇した場合は、`EventLoopFuture` を返す関数に `.get()` を呼び出して変換することができます。
@ -108,7 +108,7 @@ let futureString: EventLoopFuture<String> = promise.futureResult
に変換できます。
## `EventLoopFuture`
## `EventLoopFuture` {#eventloopfutures}
Vapor のいくつかの API が一般的な `EventLoopFuture` タイプを期待したり返したりすることに気づいたかもしれません。もしこれが futures について初めて聞いたのであれば、最初は少し混乱するかもしれません。しかし心配しないでください、このガイドは彼らの強力な API を利用する方法をお見せします。
@ -121,7 +121,7 @@ Vapor のいくつかの API が一般的な `EventLoopFuture` タイプを期
フューチャーは、コールバックベースの非同期 API への代替手段です。フューチャーは、単純なクロージャではできない方法で連鎖させたり変換したりすることができます。
## 変換
## 変換 {#transforming}
Swiftのオプショナルや配列のように、フューチャーはマップやフラットマップで変換できます。これらは、フューチャーに対して行う最も一般的な操作です。
@ -235,7 +235,7 @@ print(futureStatus) // EventLoopFuture<HTTPStatus>
`transform` に既に利用可能な値を提供しているとしても、これはまだ_変換_です。前のフューチャーが完了するまたは失敗するまで、フューチャーは完了しません。
### Chaining
### チェーン {#chaining}
フューチャーの変換の素晴らしい点は、それらがチェーンできることです。これにより、多くの変換やサブタスクを簡単に表現できます。
@ -300,8 +300,24 @@ futureString.whenComplete { result in
!!! note
Future には、好きなだけコールバックを追加できます。
### Get
API に並行性ベースの代替手段がない場合は、`try await future.get()` を使用して Future の値を待つことができます。
```swift
/// 何らかの API から Future 文字列を取得すると仮定します
let futureString: EventLoopFuture<String> = ...
/// 文字列が準備できるまで待ちます
let string: String = try await futureString.get()
print(string) /// String
```
### Wait
!!! warning
`wait()` 関数は廃止されました。推奨されるアプローチについては [`Get`](#get) を参照してください。
`.wait()`を使用して、フューチャーが完了するまで同期的に待つことができます。フューチャーが失敗する可能性があるため、この呼び出しは投げられます。
```swift
@ -345,7 +361,7 @@ promiseString.fail(...)
約束はどのスレッドからでも完了(`succeed` / `fail`)できます。これが、初期化にイベントループが必要な理由です。約束は、完了アクションがそのイベントループに戻されて実行されることを保証します。
## イベントループ
## イベントループ {#event-loop}
アプリケーションが起動すると、通常は実行中の CPU の各コアに対して1つのイベントループが作成されます。各イベントループには1つのスレッドがあります。Node.js からのイベントループに精通している場合、Vapor のものは似ています。主な違いは、Swift がマルチスレッディングをサポートしているため、Vapor は 1 つのプロセスで複数のイベントループを実行できることです。
@ -411,7 +427,7 @@ app.get("hello") { req -> EventLoopFuture<String> in
すべてのブロッキングコールが `sleep(_:)` ほど明白ではありません。使用している呼び出しがブロッキングかどうか疑わしい場合は、そのメソッド自体を調査するか、誰かに尋ねてください。以下のセクションでは、メソッドがどのようにブロッキングする可能性があるかについて、詳しく説明します。
### I/O バウンド
### I/O バウンド {#io-bound}
I/O バウンドのブロッキングとは、ネットワークやハードディスクなど、CPU よりも桁違いに遅いリソースを待つことを意味します。これらのリソースを待っている間に CPU をブロックすると、時間が無駄になります。
@ -420,7 +436,7 @@ I/O バウンドのブロッキングとは、ネットワークやハードデ
Vapor のすべてのパッケージは SwiftNIO に基づいており、ノンブロッキング I/O を使用しています。しかし、ブロッキング I/O を使用する Swift のパッケージや C ライブラリが多く存在します。関数がディスクやネットワーク IO を行っており、同期 APIコールバックやフューチャーがないを使用している場合、ブロッキングしている可能性が高いです。
### CPU バウンド
### CPU バウンド {#cpu-bound}
リクエスト中のほとんどの時間は、データベースのクエリやネットワークリクエストなどの外部リソースを待っているために費やされます。Vapor と SwiftNIO はノンブロッキングなので、このダウンタイムは他の受信リクエストを満たすために使用できます。しかし、アプリケーションのいくつかのルートは、リクエストの結果として重い CPU バウンド作業を行う必要があるかもしれません。

View File

@ -1,8 +1,8 @@
# クライアント
# クライアント {#client}
Vapor のクライアント API では、外部のリソースに対して HTTP 通信を行うことができます。これは [async-http-client](https://github.com/swift-server/async-http-client) に基づいており、[コンテンツ](content.ja.md) API と統合されています。
## 概要
## 概要 {#overview}
`Application` やルートハンドラー内の `Request` から、デフォルトクライアントにアクセスできます。
@ -16,7 +16,7 @@ app.get("test") { req in
アプリケーションのクライアントは、設定時に HTTP リクエストを送る際に便利です。ルートハンドラー内で HTTP リクエストを行う場合は、リクエストに紐づくクライアントを使うべきです。
### メソッド
### メソッド {#methods}
`GET` リクエストを行う際には、目的の URL を `get` メソッドに渡します。
@ -24,9 +24,9 @@ app.get("test") { req in
let response = try await req.client.get("https://httpbin.org/status/200")
```
`get`、`post`、`delete` など、各種 HTTP メソッドに対応したメソッドがあります。クライアントからのレスポンスは将来的に返され、HTTPステータス、ヘッダー、ボディが含まれます。
`get`、`post`、`delete` など、各種 HTTP メソッドに対応したメソッドがあります。クライアントからのレスポンスはFutureとして返され、HTTPステータス、ヘッダー、ボディが含まれます。
### コンテンツ
### コンテンツ {#content}
Vapor の [コンテンツ](content.ja.md) を使うと、クライアントリクエストやレスポンスのデータを扱うことができます。コンテンツやクエリパラメータをエンコードしたり、ヘッダーを追加するには、`beforeSend` クロージャを使います。
@ -42,32 +42,32 @@ let response = try await req.client.post("https://httpbin.org/status/200") { req
let auth = BasicAuthorization(username: "something", password: "somethingelse")
req.headers.basicAuthorization = auth
}
//レスポンスを扱う
// レスポンスを処理する。
```
レスポンスボディを `Content` を使ってデコードすることもできます。
レスポンスボディを `Content` を使ってデコードすることもできます。
```swift
let response = try await req.client.get("https://httpbin.org/json")
let json = try response.content.decode(MyJSONResponse.self)
```
もし、futures を使っている場合は、`flatMapThrowing` を使うことができます。
もし、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
// ここでJSONを使用
}
```
## 設定
## 設定 {#configuration}
アプリケーションを通じて、基本となる HTTP クライアントを設定することができます。
```swift
// Disable automatic redirect following.
// 自動リダイレクトを無効にする。
app.http.client.configuration.redirectConfiguration = .disallow
```

View File

@ -1,8 +1,8 @@
# コンテンツ
# コンテンツ {#content}
Vapor のコンテンツ API を使用すると、Codable な構造体を HTTP メッセージに対して簡単にエンコード・デコードできます。標準では [JSON](https://tools.ietf.org/html/rfc7159) 形式でエンコードされており、[URL-Encoded Form](https://en.wikipedia.org/wiki/Percent-encoding#The_application/x-www-form-urlencoded_type) や [Multipart](https://tools.ietf.org/html/rfc2388) についても即座に使えるサポートがあります。この API はカスタマイズ可能であり、特定の HTTP コンテンツタイプに対するエンコーディングの戦略を追加したり、変更したり、置き換えたりすることができます。
## 概要
## 概要 {#overview}
Vapor のコンテンツ API の仕組みを理解するためには、HTTP メッセージの基本について知っておく必要があります。以下にリクエストの例を示します。
@ -16,7 +16,7 @@ content-length: 18
このリクエストは、`content-type` ヘッダーを通じて `application/json` メディアタイプでJSON形式のデータが含まれていることを示しています。ヘッダーの後のボディ部分には、約束されたJSONデータが続きます。
### コンテンツ構造体
### コンテンツ構造体 {#content-struct}
この HTTP メッセージをデコードする最初のステップは、期待される構造にマッチする Codable 型を作成することです。
@ -28,11 +28,10 @@ struct Greeting: Content {
型を `Content` に準拠させると、コンテンツ API を扱うための追加ユーティリティが得られると同時に、`Codable` にも自動的に準拠するようになります。
コンテンツの構造ができたら、`req.content` を使ってリクエストからデコードできます。
```swift
app.post("greeting") { req in
app.post("greeting") { req in
let greeting = try req.content.decode(Greeting.self)
print(greeting.hello) // "world"
return HTTPStatus.ok
@ -61,7 +60,7 @@ struct Profile: Content {
}
```
### サポートされるメディアタイプ
### サポートされるメディアタイプ {#supported-media-types}
以下は、コンテンツ API がデフォルトでサポートしているメディアタイプです。
@ -75,11 +74,11 @@ struct Profile: Content {
すべてのメディアタイプが全ての `Codable` 機能をサポートしているわけではありません。例えば、JSON はトップレベルのフラグメントをサポートしておらず、プレーンテキストはネストされたデータをサポートしていません。
## クエリ
## クエリ {#query}
Vapor のコンテンツ API は、URL のクエリ文字列にエンコードされたデータの処理に対応しています。
### デコード
### デコード {#decoding}
URL クエリ文字列をデコードする方法を理解するために、以下の例をご覧ください。
@ -101,7 +100,7 @@ struct Hello: Content {
期待されるクエリ文字列に合わせた `Content` 構造体が用意できたら、それをデコードできます。
```swift
app.get("hello") { req -> String in
app.get("hello") { req -> String in
let hello = try req.query.decode(Hello.self)
return "Hello, \(hello.name ?? "Anonymous")"
}
@ -123,7 +122,7 @@ GET /hello HTTP/1.1
content-length: 0
```
### 単一の値
### 単一の値 {#single-value}
`Content` 構造体へのデコードだけでなく、Vapor はクエリ文字列から単一の値を取得することもサポートしています。これはサブスクリプトを使用して行われます。
@ -131,23 +130,23 @@ content-length: 0
let name: String? = req.query["name"]
```
## フック
## フック {#hooks}
Vapor は、`Content` タイプに対して `beforeEncode` および `afterDecode` を自動的に呼び出します。デフォルトの実装は何もしませんが、これらのメソッドを使用してカスタムロジックを実行することができます。
```swift
// この Content がデコードされた後に実行されます。`mutating` は構造体のみに必要で、クラスには必要ありません。
// この Content がデコードされた後に実行されます。`mutating` は構造体のみに必要で、クラスには必要ありません。
mutating func afterDecode() throws {
// 名前は渡されないことがありますが、渡される場合は空文字列であってはなりません。
// 名前は *必ず* 渡される必要があり、空文字列であってはなりません。
self.name = self.name?.trimmingCharacters(in: .whitespacesAndNewlines)
if let name = self.name, name.isEmpty {
throw Abort(.badRequest, reason: "Name must not be empty.")
}
}
// この Contents がエンコードされる前に実行されます。`mutating` は構造体のみに必要で、クラスには必要ありません。
// この Content がエンコードされる前に実行されます。`mutating` は構造体のみに必要で、クラスには必要ありません。
mutating func beforeEncode() throws {
// 名前は渡されないことがありますが、渡される場合は空文字列であってはなりません。
// 名前は *必ず* 渡される必要があり、空文字列であってはなりません。
guard
let name = self.name?.trimmingCharacters(in: .whitespacesAndNewlines),
!name.isEmpty
@ -158,11 +157,11 @@ mutating func beforeEncode() throws {
}
```
## デフォルトの上書き
## デフォルトの上書き {#override-defaults}
Vapor の Content API によって使用されるデフォルトのエンコーダーとデコーダーは設定可能です。
### グローバル
### グローバル {#global}
`ContentConfiguration.global` を使用すると、Vapor がデフォルトで使用するエンコーダーやデコーダーを変更できます。これは、アプリケーション全体でデータの解析やシリアライズ方法を変更するのに便利です。
@ -177,7 +176,7 @@ ContentConfiguration.global.use(encoder: encoder, for: .json)
`ContentConfiguration` の変更は通常、`configure.swift` で行われます。
### 1回限り
### 1回限り {#one-off}
`req.content.decode` のようなエンコーディングやデコーディングのメソッド呼び出しは、1回限りの使用のためにカスタムコーダーを渡すことをサポートしています。
@ -190,7 +189,7 @@ decoder.dateDecodingStrategy = .secondsSince1970
let hello = try req.content.decode(Hello.self, using: decoder)
```
## カスタムコーダー
## カスタムコーダー {#custom-coders}
アプリケーションやサードパーティのパッケージは、Vapor がデフォルトでサポートしていないメディアタイプに対応するためにカスタムコーダーを作成することができます。
@ -212,9 +211,9 @@ public protocol ContentDecoder {
これらのプロトコルに準拠することで、カスタムコーダーを上記で指定されたように `ContentConfiguration` に登録できます。
### URL クエリ
### URL クエリ {#url-query}
Vapor は、URL クエリ文字列のコンテンツを処理することができる coder のための 2 つのプロトコルを指定しています: `URLQueryDecoder``URLQueryEncoder`
Vapor は、URL クエリ文字列のコンテンツを処理することができるコーダーのための 2 つのプロトコルを指定しています: `URLQueryDecoder``URLQueryEncoder`
```swift
public protocol URLQueryDecoder {
@ -230,7 +229,7 @@ public protocol URLQueryEncoder {
これらのプロトコルに準拠することで、`use(urlEncoder:)` および `use(urlDecoder:)` メソッドを使用して、URL クエリ文字列の処理のためにカスタムコーダーを `ContentConfiguration` に登録できます。
### カスタム `ResponseEncodable`
### カスタム `ResponseEncodable` {#custom-responseencodable}
別のアプローチには、タイプに `ResponseEncodable` を実装するというものがあります。この単純な `HTML` ラッパータイプを考えてみてください。
@ -254,7 +253,7 @@ extension HTML: ResponseEncodable {
}
```
`async`/`await` を使用している場合は、`AsyncResponseEncodable` を使用できます。
`async`/`await` を使用している場合は、`AsyncResponseEncodable` を使用できます。
```swift
extension HTML: AsyncResponseEncodable {

View File

@ -1,10 +1,10 @@
# コントローラー
# コントローラー {#controllers}
コントローラーはコードを整理するのに適した方法です。これらは、リクエストを受けてレスポンスを返すメソッドの集まりです。
コントローラーを置く良い場所は、[Controllers](../getting-started/folder-structure.ja.md#controllers) フォルダーです。
## 概要
## 概要 {#overview}
例としてコントローラーを見てみましょう。

View File

@ -1,4 +1,4 @@
# 環境
# 環境 {#environment}
VaporのEnvironment APIは、アプリの動的な設定を支援します。デフォルトでは、あなたのアプリは`development`環境を使用します。`production`や`staging`のような他の有用な環境を定義し、各ケースでアプリがどのように設定されるかを変更できます。また、プロセスの環境や`.env`dotenvファイルから変数を読み込むことも、ニーズに応じて可能です。
@ -13,7 +13,7 @@ default:
}
```
## 環境の変化
## 環境の変化 {#changing-environment}
デフォルトでは、アプリは `development` 環境で実行されます。アプリ起動時に `--env``-e`)フラグを渡すことで、これを変更できます。
@ -39,7 +39,7 @@ Vapor は以下の環境を含みます。:
swift run App serve -e prod
```
## プロセス変数
## プロセス変数 {#process-variables}
`Environment` は、プロセスの環境変数にアクセスするためのシンプルな文字列ベースの API を提供します。
@ -64,7 +64,7 @@ swift run App serve
Xcode でアプリを実行する場合は、`App` スキームを編集して環境変数を設定できます。
## .env (dotenv)
## .env (dotenv) {#env-dotenv}
Dotenv ファイルには、環境に自動的にロードされるキーと値のペアのリストが含まれています。これらのファイルは、手動で設定することなく環境変数を設定するのを容易にします。
@ -107,7 +107,7 @@ vim .env.development
dotenv ファイルの読み込みに問題がある場合は、`--log debug` を使用してデバッグログを有効にすると、より多くの情報が得られます。
## カスタム環境
## カスタム環境 {#custom-environments}
カスタム環境を定義するには、`Environment`を拡張します。
@ -129,7 +129,9 @@ enum Entrypoint {
try LoggingSystem.bootstrap(from: &env)
let app = Application(env)
defer { app.shutdown() }
defer {
app.shutdown()
}
try await configure(app)
try await app.runFromAsyncMainEntrypoint()

View File

@ -1,4 +1,4 @@
# エラー
# エラー {#errors}
Vapor は Swift の `Error` プロトコルをベースにしたエラー処理を採用しています。ルートハンドラは、エラーを `throw` するか、失敗した `EventLoopFuture` を返すことができます。Swiftの `Error` を throw するか返すと、`500` ステータスのレスポンスが生成され、エラーがログに記録されます。`AbortError` と `DebuggableError` は、それぞれ結果として得られるレスポンスとログを変更するために使用できます。エラーの処理は `ErrorMiddleware` によって行われます。このミドルウェアはデフォルトでアプリケーションに追加されており、必要に応じてカスタムロジックに置き換えることができます。
@ -136,52 +136,8 @@ struct MyError: DebuggableError {
`DebuggableError` には、エラーのデバッグ性を向上させるために使用できる `possibleCauses``suggestedFixes` など、他にもいくつかのプロパティがあります。より詳細に知りたい場合は、プロトコル自体をご覧ください。
## スタックトレース
Vaporは、通常のSwiftエラーやクラッシュに対するスタックトレースの表示をサポートしています。
### Swift バックトレース
Vapor は、Linux 上で致命的なエラーやアサーションの後にスタックトレースを提供するために、[SwiftBacktrace](https://github.com/swift-server/swift-backtrace) ライブラリを使用しています。これが機能するためには、アプリはコンパイル中にデバッグシンボルを含める必要があります。
```sh
swift build -c release -Xswiftc -g
```
### エラートレース
デフォルトでは、`Abort` は初期化されたときに現在のスタックトレースをキャプチャします。カスタムエラータイプは、`DebuggableError` に準拠し、`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
}
}
```
アプリケーションの[ログレベル](logging.ja.md#level)が `.debug` 以下に設定されている場合、エラースタックトレースはログ出力に含まれます。
ログレベルが `.debug` より大きい場合、スタックトレースはキャプチャされません。この挙動を変更するには、`configure` 内で `StackTrace.isCaptureEnabled` を手動で設定してください。
```swift
// Always capture stack traces, regardless of log level.
StackTrace.isCaptureEnabled = true
```
## エラーミドルウェア
## エラーミドルウェア {#error-middleware}
`ErrorMiddleware` は、デフォルトでアプリケーションに追加される唯一のミドルウェアです。このミドルウェアは、ルートハンドラーによって投げられたり返されたりした Swift のエラーを HTTP レスポンスに変換します。このミドルウェアがない場合、投げられたエラーは応答なしに接続が閉じられることになります。

View File

@ -1,12 +1,12 @@
# ロギング
# ロギング {#logging}
Vapor のロギング API は [SwiftLog](https://github.com/apple/swift-log) を基に構築されています。これは、Vapor が SwiftLog の[バックエンド実装](https://github.com/apple/swift-log#backends)と互換性があることを示しています。
## ロガー
## ロガー {#logger}
`Logger` のインスタンスはログメッセージを出力するために使用されます。Vapor はロガーにアクセスするためのいくつかの簡単な方法を提供しています。
### リクエスト
### リクエスト {#request}
各入力 `Request` には、そのリクエストに固有のログを使用するためのユニークなロガーがあります。
@ -26,7 +26,7 @@ app.get("hello") { req -> String in
!!! info
ロガーメタデータは、デバッグログレベルまたはそれ以下でのみ表示されます。
### アプリケーション
### アプリケーション {#application}
アプリの起動や設定中のログメッセージには、`Application` のロガーを使用します。
@ -35,7 +35,7 @@ app.logger.info("Setting up migrations...")
app.migrations.use(...)
```
### カスタムロガー
### カスタムロガー {#custom-logger}
`Application``Request` にアクセスできない状況では、新しい `Logger` を初期化できます。
@ -46,11 +46,11 @@ logger.info(...)
カスタムロガーは設定されたロギングバックエンドに出力されますが、リクエスト UUID のような重要なメタデータは付加されません。可能な限りリクエストやアプリケーション固有のロガーを使用してください。
## レベル
## レベル {#level}
SwiftLog はいくつかの異なるログレベルをサポートしています。
|nama|description|
|name|description|
|-|-|
|trace|プログラムの実行を追跡する際に通常のみ役立つ情報を含むメッセージに適しています。|
|debug|プログラムをデバッグする際に通常のみ役立つ情報を含むメッセージに適しています。|
@ -64,7 +64,7 @@ SwiftLog はいくつかの異なるログレベルをサポートしていま
デフォルトでは、Vapor は `info` レベルのログを使用します。`production` 環境で実行する場合は、パフォーマンス向上のためにnoticeが使用されます。
### ログレベルの変更
### ログレベルの変更 {#changing-log-level}
環境モードに関係なく、ログの量を増減するためにログレベルをオーバーライドできます。
@ -83,7 +83,7 @@ swift run App serve
これらの操作は、Xcodeで `App` スキームを編集することで行うことができます。
## 設定
## 設定 {#configuration}
SwiftLog は、プロセスごとに一度 `LoggingSystem` をブートストラップすることによって設定されます。Vapor プロジェクトでは、これは通常 `entrypoint.swift` で行われます。
@ -94,7 +94,7 @@ try LoggingSystem.bootstrap(from: &env)
`bootstrap(from:)` は、コマンドライン引数や環境変数に基づいてデフォルトのログハンドラーを設定するために Vapor が提供するヘルパーメソッドです。デフォルトのログハンドラーは、ANSI カラーサポートを備えた端末へのメッセージ出力をサポートしています。
### カスタムハンドラー
### カスタムハンドラー {#custom-handler}
Vaporのデフォルトのログハンドラーをオーバーライドし、独自のものを登録することができます。

View File

@ -1,8 +1,8 @@
# ルーティング
# ルーティング {#routing}
ルーティングは、入ってきたリクエストに対して適切なリクエストハンドラを見つける処理です。Vapor のルーティングの核心には、[RoutingKit](https://github.com/vapor/routing-kit) からの高性能なトライノードルータがあります。
## 概要
## 概要 {#overview}
Vapor でのルーティングの仕組みを理解するために、まず HTTP リクエストの基本について理解する必要があります。以下のサンプルリクエストを見てください。
@ -18,7 +18,7 @@ content-length: 0
http://vapor.codes/hello/vapor
```
### HTTP メソッド
### HTTP メソッド {#http-method}
リクエストの最初の部分は HTTP メソッドです。`GET` は最も一般的な HTTP メソッドですが、頻繁に使用されるいくつかの HTTP メソッドがあります。これらの HTTP メソッドは、しばしば [CRUD](https://en.wikipedia.org/wiki/Create,_read,_update_and_delete) セマンティクスと関連付けられています。
@ -30,13 +30,13 @@ http://vapor.codes/hello/vapor
|`PATCH`|更新(Update)|
|`DELETE`|削除(Delete)|
### リクエストパス
### リクエストパス {#request-path}
HTTP メソッドの直後には、リクエストの URI があります。これは、`/` で始まるパスと、`?` の後のオプションのクエリ文字列で構成されています。HTTP メソッドとパスは、Vapor がリクエストをルーティングするために使用するものです。
URI の後には HTTP バージョン、0個以上のヘッダが続き、最後にボディが続きます。これは `GET` リクエストなので、ボディはありません。
### ルーターメソッド
### ルーターメソッド {#router-methods}
このリクエストが Vapor でどのように処理されるか見てみましょう。
@ -64,7 +64,7 @@ content-type: text/plain; charset=utf-8
Hello, vapor!
```
### ルートパラメータ
### ルートパラメータ {#route-parameters}
HTTP メソッドとパスに基づいてリクエストを正常にルーティングしたので、次にパスを動的にしてみましょう。"vapor" の名前がパスとレスポンスの両方でハードコードされていることに注意してください。これを動的にして、`/hello/<任意の名前>` にアクセスすると、レスポンスが返されるようにしてみましょう。
@ -93,11 +93,11 @@ Hello, swift!
基本を理解したところで、各セッションをチェックし、パラメータやグループなどについて詳しく学んでください。
## ルート
## ルート {#routes}
ルートは、特定の HTTP メソッドと URI パスに対するリクエストハンドラを指定します。また、追加のメタデータを格納することもできます。
### メソッド
### メソッド {#methods}
ルートは、様々な HTTP メソッドヘルパーを使用して、`Application` に直接登録できます。
@ -135,7 +135,7 @@ app.on(.OPTIONS, "foo", "bar", "baz") { req in
}
```
### パスコンポーネント
### パスコンポーネント {#path-component}
各ルート登録メソッドは、`PathComponent` の多様なリストを受け入れます。このタイプは文字列リテラルによって表現可能であり、4つのケースがあります:
@ -144,7 +144,7 @@ app.on(.OPTIONS, "foo", "bar", "baz") { req in
- Anything (`*`)
- キャッチオール (`**`)
#### 定数
#### 定数 {#constant}
これは静的なルートコンポーネントです。この位置で正確に一致する文字列のみが許可されます。
@ -155,7 +155,7 @@ app.get("foo", "bar", "baz") { req in
}
```
#### パラメータ
#### パラメータ {#parameter}
これは動的なルートコンポーネントです。この位置での任意の文字列が許可されます。パラメータコンポーネントは `:` 接頭辞で指定されます。`:` に続く文字列は、パラメータの名前として使用されます。後でリクエストからパラメータの値にアクセスするために名前を使用できます。
@ -181,7 +181,7 @@ app.get("foo", "*", "baz") { req in
}
```
#### キャッチオール
#### キャッチオール {#catchall}
これは、1つ以上のコンポーネントに一致する動的なルートコンポーネントです。 `**` だけで指定します。この位置以降の文字列はリクエストでマッチします。
@ -194,7 +194,7 @@ app.get("foo", "**") { req in
}
```
### パラメータ
### パラメータ {#parameters}
パラメータパスコンポーネント(`:` で接頭辞されたもの) を使用すると、その位置の URI の値が `req.parameters` に格納されます。パスコンポーネントの名前を使用して、値にアクセスできます。
@ -209,7 +209,7 @@ app.get("hello", ":name") { req -> String in
```
!!! tip
ルートパスに `:name` が含まれているので、`rep.parameters.get` が `nil` を返すことはないと核心しています。ただし、ミッドウェア内でルートパラメータにアクセスしたり、複数のルートによってトリガされるコード内でこれを行う場合は、`nil` の可能性を処理する必要があります。
ルートパスに `:name` が含まれているので、`req.parameters.get` が `nil` を返すことはないと確信しています。ただし、ミッドウェア内でルートパラメータにアクセスしたり、複数のルートによってトリガされるコード内でこれを行う場合は、`nil` の可能性を処理する必要があります。
!!! tip
URL クエリパラメータを取得したい場合、例えば `/hello/?name=foo` 、URLのクエリ文字列で URL エンコードされたデータを処理するために、Vapor の Content API を使用する必要があります。詳しくは[`Content` リファレンス](content.md)を参照してください。
@ -240,7 +240,7 @@ app.get("hello", "**") { req -> String in
}
```
### Body ストリーミング
### Body ストリーミング {#body-streaming}
`on` メソッドを使用してルートを登録するとき、リクエストの本文がどのように処理されるかを指定できます。デフォルトでは、ハンドラを呼び出す前にリクエストの本文がメモリに収集されます。これは、アプリケーションが非同期に適切なリクエストを読み取るにもかかわらず、リクエストのコンテンツの複号化を同期的に行うために便利です。
@ -251,7 +251,7 @@ app.get("hello", "**") { req -> String in
app.routes.defaultMaxBodySize = "500kb"
```
収集されるストリーミングボディが設定された制限を超えた場合、`413 Payload Too Large` エラーが投げられ
収集されるストリーミングボディが設定された制限を超えた場合、`413 Payload Too Large` エラーが投げられます
個々のルートに対してリクエストボディの収集ストラテジーを設定するには、`body` パラメータを使います。
@ -275,7 +275,7 @@ app.on(.POST, "upload", body: .stream) { req in
リクエストの本文がストリームされる場合、`req.body.data` は `nil` になります。各チャンクがルートに送信されるたびに `req.body.drain` を使用して処理する必要があります。
### 大文字・小文字を区別しないルーティング
### 大文字・小文字を区別しないルーティング {#case-insensitive-routing}
ルーティングのデフォルトの振る舞いは、大文字・小文字を区別するとともに、大文字・小文字を保持します。`Constant` パスのコンポーネントは、ルーティングの目的のために、大文字・小文字を区別しないが大文字・小文字を保持する方法で扱うことができます。この振る舞いを有効にするには、アプリケーションの起動前に設定して下さい。:
```swift
@ -284,7 +284,7 @@ app.routes.caseInsensitive = true
元のリクエストに変更は加えられません。ルートハンドラは、リクエストのパスコンポーネントを変更せずに受け取ります。
### ルートの表示
### ルートの表示 {#viewing-routes}
アプリケーションのルートにアクセスするには、`Routes` サービスを使用するか、`app.routes` を使用します。
@ -309,7 +309,7 @@ $ swift run App routes
+--------+----------------+
```
### メタデータ
### メタデータ {#metadata}
すべてのルート登録メソッドは、作成された `Route` を返します。これにより、ルートの`userInfo` 辞書にメタデータを追加できます。説明を追加するようなデフォルトのメソッドも用意されています。
@ -319,13 +319,13 @@ app.get("hello", ":name") { req in
}.description("says hello")
```
## ルートグループ
## ルートグループ {#route-groups}
ルートのグループ化により、パスの接頭辞または特定のミドルウェアを持つルートのセットを作成できます。グループ化は、ビルダーとクロージャベースの構文をサポートしています。
すべてのグループ化メソッドは `RouteBuilder` を返します。つまり、グループを他のルート構築メソッドと無限に組み合わせたり、ネストにしたりすることができます。
### パス接頭辞
### パス接頭辞 {#path-prefix}
パス接頭辞付きのルートグループを使用すると、1つ以上のパスコンポーネントをルートグループの先頭に追加できます。
@ -386,7 +386,7 @@ app.group("users") { users in
}
```
### ミドウェア
### ミドウェア {#middleware}
パスコンポーネントの接頭辞に、ルートグループにミドルウェアを追加することもできます。
@ -411,9 +411,9 @@ auth.get("dashboard") { ... }
auth.get("logout") { ... }
```
## リダイレクト
## リダイレクト {#redirections}
リダイレクトは、SEO のために古いロケーションを新しいロケーションに転送したり、認証されていないユーザーをログインページにリダイレクトしたり、新しいバージョンの API との広報互換性を維持したりするなど、多くのシナリオで役立ちます。
リダイレクトは、SEO のために古いロケーションを新しいロケーションに転送したり、認証されていないユーザーをログインページにリダイレクトしたり、新しいバージョンの API との後方互換性を維持したりするなど、多くのシナリオで役立ちます。
リクエストをリダイレクトするには、次のようにします:
@ -424,13 +424,13 @@ req.redirect(to: "/some/new/path")
また、リダイレクトのタイプを指定することもできます。例えば、ページを永久にリダイレクトして SEO が正しく更新されるようにするには次のようにします:
```swift
req.redirect(to: "/some/new/path", type: .permanent)
req.redirect(to: "/some/new/path", redirectType: .permanent)
```
異なる `RedirectType` は以下の通りです:
異なる `Redirect` は以下の通りです:
* `.permanent` - **301 Permanent** リダイレクトします
* `.normal` - **303 see other** リダイレクトします。これは Vapor デフォルトで、クライアントにリダイレクトを **GET** リクエストでフォローするように指示します。
* `.temporary` - **307 Temporary** リダイレクトします。これにより、リクエストで使用された HTTP メソッドをクライアントが保持するように支持されます。
* `.permanent` - **301 Permanent** リダイレクトを返します
* `.normal` - **303 see other** リダイレクトを返します。これは Vapor デフォルトで、クライアントにリダイレクトを **GET** リクエストでフォローするように指示します。
* `.temporary` - **307 Temporary** リダイレクトを返します。これにより、クライアントはリクエストで使用された HTTP メソッドを保持するよう指示されます。
> 適切なリダイレクションステータスコードを選択するには、[the full list](https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#3xx_redirection) をチェックして下さい。

View File

@ -1,12 +1,12 @@
# バリデーション
# バリデーション {#validation}
Vapor のバリデーション API は、データをデコードする前に、[コンテンツ](content.ja.md) API を使って入力リクエストの検証を行うのに役立ちます。
## はじめに
## はじめに {#introduction}
Swift の型安全な `Codable` プロトコルを深く統合している Vapor は、動的型付け言語に比べてデータバリデーションについてそれほど心配する必要はありません。しかし、明示的なバリデーションを選択する理由はいくつかあります。
### 人間が読みやすいエラー
### 人間が読みやすいエラー {#human-readable-errors}
[コンテンツ](content.ja.md) API を使用して構造体をデコードする際には、データが無効である場合にエラーが発生します。しかしながら、これらのエラーメッセージは時として人間が読みやすいものではありません。例えば、次のような文字列ベースの enum を見て下さい。
@ -30,7 +30,7 @@ favoriteColor is not red, blue, or green
さらに、`Codable` は最初のエラーが発生した時点で型のデコードを試みるのをやめます。つまり、リクエストに多くの無効なプロパティがあっても、ユーザーは最初のエラーしか見ることができません。バリデーション API は、一度のリクエストで全てのバリデーション失敗を報告します。
### 特定のバリデーション
### 特定のバリデーション {#specific-validation}
`Codable` は型のバリデーションをうまく扱いますが、時にはそれ以上のことをしたい事もあります。例えば、文字列の内容を検証したり、整数のサイズを検証したりすることです。バリデーション API には、メールアドレス、文字セット、整数の範囲など、データの検証に役立つバリデータがあります。
@ -60,7 +60,7 @@ app.post("users") { req -> CreateUser in
}
```
### バリデーションの追加
### バリデーションの追加 {#adding-validations}
最初のステップは、この場合は `CreateUser` である、デコードする型を `Validatable` に準拠させることです。これは拡張を使って行うことができます。
@ -80,7 +80,7 @@ validations.add("email", as: String.self, is: .email)
最初のパラメータは期待される値のキーで、この場合は `"email"` です。これは検証される型のプロパティ名と一致している必要があります。二番目のパラメータ `as` は期待される型で、この場合は `String` です。型は通常、プロパティの型と一致しますが、常にそうとは限りません。最後に、三番目のパラメータ `is` の後に一つまたは複数のバリデータを追加できます。この場合、値がメールアドレスであるかをチェックする単一のバリデータが追加されています。
### リクエストコンテンツのバリデーション
### リクエストコンテンツのバリデーション {#validating-request-content}
型を `Validatable` に準拠させたら、静的な `validate(content:)` 関数を使ってリクエストコンテンツをバリデーションできます。ルートハンドラの `req.content.decode(CreateUser.self)` の前に次の行を追加してください。
@ -111,7 +111,7 @@ Content-Type: application/json
email is not a valid email address
```
### リクエストクエリのバリデーション
### リクエストクエリのバリデーション {#validating-request-query}
`Validatable` に準拠している型には、リクエストのクエリ文字列をバリデーションする `validate(query:)` もあります。ルートハンドラに次の行を追加してください。
@ -133,7 +133,7 @@ GET /users?age=4&email=foo&favoriteColor=green&name=Foo&username=foo HTTP/1.1
email is not a valid email address
```
### 整数のバリデーション
### 整数のバリデーション {#integer-validation}
素晴らしい、次に `age` に対する検証を追加してみましょう。
@ -147,7 +147,7 @@ validations.add("age", as: Int.self, is: .range(13...))
age is less than minimum of 13, email is not a valid email address
```
### 文字列のバリデーション
### 文字列のバリデーション {#string-validation}
次に、`name` と `username` に対する検証を追加しましょう。
@ -160,7 +160,7 @@ validations.add("username", as: String.self, is: .count(3...) && .alphanumeric)
ユーザーネームの検証では、`&&` を使って2つのバリデーターを組み合わせます。これにより、文字列が少なくとも3文字以上であり、_かつ_ 英数字のみで構成されていることが必要です。
### Enumのバリデーション
### Enumのバリデーション {#enum-validation}
最後に、提供された `favoriteColor` が有効かどうかをチェックする少し高度な検証を見てみましょう。
@ -186,7 +186,7 @@ validations.add(
)
```
### カスタムエラー
### カスタムエラー {#custom-errors}
`Validations``Validator` にカスタムで人が読めるエラーを追加したい場合があります。そのためには、デフォルトのエラーを上書きする追加の `customFailureDescription` パラメータを提供するだけです。
@ -205,13 +205,13 @@ validations.add(
)
```
## バリデーター
## バリデーター {#validators}
以下は、現在サポートされているバリデーターと、それらが何をするのかの簡単な説明のリストです。
|Validation|説明|
|-|-|
|`.ascii`|ASC 文字のみを使います。|
|`.ascii`|ASCII 文字のみを使います。|
|`.alphanumeric`|英数字のみを含みます。|
|`.characterSet(_:)`|指定された `CharacterSet` からの文字のみを含みます。|
|`.count(_:)`|コレクションのカウントが指定された範囲内です。|
@ -221,6 +221,7 @@ validations.add(
|`.nil`|値が `null` です。|
|`.range(_:)`|値が提供された `Range` の内です。|
|`.url`|有効な URL を含みます。|
|`.custom(_:)`|カスタム検証ロジック。|
バリデーターはまた、演算子を使用して複雑な検証を組み立てるために組み合わせることができます。
@ -230,7 +231,11 @@ validations.add(
|`&&`|中置|2つのバリデーターを組み合わせ、両方を要求する。|
|`||`|中置|2つのバリデーターを組み合わせ、1つを要求する。|
## カスタムバリデーション
## カスタムバリデーション {#custom-validators}
カスタムバリデーターを作成する方法は2つあります。
### Validation APIの拡張 {#extending-validation-api}
郵便番号のカスタムバリデーターを作成することで、バリデーションフレームワークの機能を拡張できます。このセクションでは、郵便番号を検証するカスタムバリデーターを作成する手順を説明します。
@ -289,3 +294,45 @@ extension Validator where T == String {
```swift
validations.add("zipCode", as: String.self, is: .zipCode)
```
### `Custom` バリデーター {#custom-validator}
`Custom` バリデーターは、1つの `Content` オブジェクトでのみプロパティを検証したい場合に最適です。この実装には、Validation API を拡張する場合と比較して、次の2つの利点があります
- カスタム検証ロジックの実装がシンプル
- より短い構文
このセクションでは、`nameAndSurname` プロパティを見て、従業員が当社の一員であるかどうかをチェックするカスタムバリデーターを作成する手順を説明します。
```swift
let allCompanyEmployees: [String] = [
"Everett Erickson",
"Sabrina Manning",
"Seth Gates",
"Melina Hobbs",
"Brendan Wade",
"Evie Richardson",
]
struct Employee: Content {
var nameAndSurname: String
var email: String
var age: Int
var role: String
static func validations(_ validations: inout Validations) {
validations.add(
"nameAndSurname",
as: String.self,
is: .custom("名前と姓から従業員がXYZ社の一員であるかを検証します。") { nameAndSurname in
for employee in allCompanyEmployees {
if employee == nameAndSurname {
return true
}
}
return false
}
)
}
}
```

View File

@ -44,7 +44,7 @@ VaporはSwiftの行動規範を採用しており、[https://www.swift.org/code-
まず、Vaporまたは作業したいリポジトリをフォークします。これはGitHub UIで行うことができ、GitHubには[これを行う方法に関する優れたドキュメント](https://docs.github.com/ja/pull-requests/collaborating-with-pull-requests/working-with-forks/fork-a-repo)があります。
その後、通常のコミットとプッシュのプロセスで、フォークで変更を加えることができます。修正を提出する準備ができたら、VaporのリポジトリにPRを作成できます。ここでも、GitHubには[これを行う方法に関する優れたドキュメント](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/proposing-changes-to-your-work-with-pull-requests/creating-a-pull-request-from-a-fork)があります。
その後、通常のコミットとプッシュのプロセスで、フォークで変更を加えることができます。修正を提出する準備ができたら、VaporのリポジトリにPRを作成できます。ここでも、GitHubには[これを行う方法に関する優れたドキュメント](https://docs.github.com/ja/pull-requests/collaborating-with-pull-requests/proposing-changes-to-your-work-with-pull-requests/creating-a-pull-request-from-a-fork)があります。
## プルリクエストの提出 {#submitting-a-pull-request}

View File

@ -175,10 +175,10 @@ DigitalOcean DropletでVaporアプリが実行できたことをおめでとう
このガイドの残りの部分では、デプロイメントを改善するための追加リソースを紹介します。
### Supervisor {#supervisor}
### Supervisor
Supervisorは、Vapor実行ファイルを実行および監視できるプロセス制御システムです。Supervisorを設定すると、サーバーの起動時にアプリが自動的に開始され、クラッシュした場合に再起動されます。[Supervisor](../deploy/supervisor.md)について詳しく学びましょう。
### Nginx {#nginx}
### Nginx
Nginxは、極めて高速で、実戦で証明されており、設定が簡単なHTTPサーバーおよびプロキシです。VaporはHTTPリクエストを直接処理することをサポートしていますが、Nginxの背後でプロキシすることで、パフォーマンス、セキュリティ、使いやすさが向上します。[Nginx](../deploy/nginx.md)について詳しく学びましょう。

View File

@ -10,7 +10,7 @@ Herokuアカウントが必要です。まだお持ちでない場合は、こ
Heroku CLIツールがインストールされていることを確認してください。
### HomeBrew {#homebrew}
### HomeBrew
```bash
brew tap heroku/brew && brew install heroku
@ -38,7 +38,7 @@ heroku auth:whoami
dashboard.heroku.comにアクセスしてアカウントにログインし、右上のドロップダウンから新しいアプリケーションを作成します。Herokuはリージョンやアプリケーション名などいくつかの質問をしますので、プロンプトに従ってください。
### Git {#git}
### Git
HerokuはGitを使用してアプリをデプロイするため、プロジェクトをGitリポジトリに配置する必要がありますまだの場合
@ -118,7 +118,7 @@ echo "5.8.1" > .swift-version
これにより、`5.8.1`を内容とする**.swift-version**が作成されます。
### Procfile {#procfile}
### Procfile
Herokuはアプリの実行方法を知るために**Procfile**を使用します。私たちの場合、次のようになります:
@ -164,7 +164,7 @@ heroku ps:scale web=1
更新したい場合は、最新の変更をmainに取り込んでHerokuにプッシュするだけで、再デプロイされます。
## Postgres {#postgres}
## Postgres
### PostgreSQLデータベースの追加 {#add-postgresql-database}

View File

@ -33,7 +33,6 @@ WantedBy=multi-user.target
`--env production`フラグは詳細なログ出力を無効にします。
### 環境変数 {#environment}
値のクォートは任意ですが、推奨されます。
systemd経由で変数をエクスポートする方法は2つあります。すべての変数が設定された環境ファイルを作成する方法

View File

@ -34,7 +34,7 @@ import FluentPostgresDriver
if let postgres = req.db as? PostgresDatabase {
// 基礎となるデータベースドライバーはPostgreSQLです。
postgres.simpleQuery("SELECT * FROM planets").all()
let planets = try await postgres.simpleQuery("SELECT * FROM planets").all()
} else {
// 基礎となるデータベースはPostgreSQLではありません。
}

View File

@ -5,11 +5,11 @@
```swift
// マイグレーションの例
struct MyMigration: Migration {
func prepare(on database: Database) -> EventLoopFuture<Void> {
func prepare(on database: any Database) -> EventLoopFuture<Void> {
// データベースに変更を加える
}
func revert(on database: Database) -> EventLoopFuture<Void> {
func revert(on database: any Database) -> EventLoopFuture<Void> {
// `prepare`で行った変更を取り消す(可能な場合)
}
}
@ -19,11 +19,11 @@ struct MyMigration: Migration {
```swift
struct MyMigration: AsyncMigration {
func prepare(on database: Database) async throws {
func prepare(on database: any Database) async throws {
// データベースに変更を加える
}
func revert(on database: Database) async throws {
func revert(on database: any Database) async throws {
// `prepare`で行った変更を取り消す(可能な場合)
}
}

View File

@ -344,7 +344,7 @@ User.query(on: database).filter(\.$pet.$name == "Zizek").all()
|1|Tanner|Zizek|Cat|
|2|Logan|Runa|Dog|
## Codable {#codable}
## Codable
モデルはデフォルトで`Codable`に準拠しています。つまり、`Content`プロトコルへの準拠を追加することで、モデルをVaporの[コンテンツAPI](../basics/content.md)で使用できます。

View File

@ -286,7 +286,7 @@ init(id: UUID? = nil, name: String) {
```swift
struct CreateGalaxy: AsyncMigration {
// Galaxy モデルを格納するためのデータベースの準備
func prepare(on database: Database) async throws {
func prepare(on database: any Database) async throws {
try await database.schema("galaxies")
.id()
.field("name", .string)
@ -294,7 +294,7 @@ struct CreateGalaxy: AsyncMigration {
}
// 必要に応じて、prepare メソッドで行った変更を元に戻します
func revert(on database: Database) async throws {
func revert(on database: any Database) async throws {
try await database.schema("galaxies").delete()
}
}
@ -478,7 +478,7 @@ self.$galaxy.id = galaxyID
```swift
struct CreateStar: AsyncMigration {
// Star モデルを格納するためのデータベースの準備
func prepare(on database: Database) async throws {
func prepare(on database: any Database) async throws {
try await database.schema("stars")
.id()
.field("name", .string)
@ -487,7 +487,7 @@ struct CreateStar: AsyncMigration {
}
// 必要に応じて、prepare メソッドで行った変更を元に戻します
func revert(on database: Database) async throws {
func revert(on database: any Database) async throws {
try await database.schema("stars").delete()
}
}

View File

@ -21,7 +21,7 @@ database.query(Planet.self)
!!! note
クエリを含むファイルで`import Fluent`を行う必要があります。これにより、コンパイラがFluentのヘルパー関数を認識できるようになります。
## All {#all}
## All
`all()`メソッドはモデルの配列を返します。
@ -37,7 +37,7 @@ let planets = try await Planet.query(on: database).all()
let names = try await Planet.query(on: database).all(\.$name)
```
### First {#first}
### First
`first()`メソッドは、単一のオプショナルなモデルを返します。クエリが複数のモデルを返す場合、最初のものだけが返されます。クエリ結果がない場合は、`nil`が返されます。

View File

@ -6,7 +6,7 @@ Fluent の [model API](model.md) は、リレーションを通じてモデル
- [Parent](#parent) / [Children](#children)1対多
- [Siblings](#siblings)(多対多)
## Parent {#parent}
## Parent
`@Parent` リレーションは、別のモデルの `@ID` プロパティへの参照を保存します。
@ -43,7 +43,7 @@ init(name: String, starID: Star.IDValue) {
[`.references`](schema.md#field-constraint) 制約はオプションであることに注意してください。詳細については [schema](schema.md) を参照してください。
### Optional Parent {#optional-parent}
### Optional Parent
`@OptionalParent` リレーションは、別のモデルの `@ID` プロパティへのオプショナルな参照を保存します。`@Parent` と同様に動作しますが、リレーションが `nil` になることを許可します。
@ -94,7 +94,7 @@ try await planet.create(on: req.db)
同じことがクライアントにモデルを返す際にも適用されます。クライアントはネストされた構造を処理できる必要があるか、返す前にモデルを DTO に変換する必要があります。DTO の詳細については、[Model ドキュメント](model.md#data-transfer-object) を参照してください。
## Optional Child {#optional-child}
## Optional Child
`@OptionalChild` プロパティは、2つのモデル間に1対1のリレーションを作成します。ルートモデルには値を保存しません。
@ -135,7 +135,7 @@ try await database.schema(Governor.schema)
クライアントのスキーマから親 ID フィールドのユニーク制約を省略すると、予測できない結果につながる可能性があります。
一意性制約がない場合、子テーブルには任意の親に対して複数の子行が含まれる可能性があります。この場合、`@OptionalChild` プロパティは一度に1つの子にしかアクセスできず、どの子が読み込まれるかを制御する方法がありません。任意の親に対して複数の子行を保存する必要がある場合は、代わりに `@Children` を使用してください。
## Children {#children}
## Children
`@Children` プロパティは、2つのモデル間に1対多のリレーションを作成します。ルートモデルには値を保存しません。
@ -161,7 +161,7 @@ try await sun.$planets.create(earth, on: database)
このリレーションは値を保存しないため、データベーススキーマエントリは必要ありません。
## Siblings {#siblings}
## Siblings
`@Siblings` プロパティは、2つのモデル間に多対多のリレーションを作成します。これはピボットと呼ばれる第3のモデルを通じて行われます。
@ -281,7 +281,7 @@ try await earth.$tags.detach(inhabited, on: database)
earth.$tags.isAttached(to: inhabited)
```
## Get {#get}
## Get
`get(on:)` メソッドを使用して、リレーションの値を取得します。
@ -303,7 +303,7 @@ print(planets)
try await sun.$planets.get(reload: true, on: database)
```
## Query {#query}
## Query
リレーションで `query(on:)` メソッドを使用して、関連モデルのクエリビルダーを作成します。
@ -314,7 +314,7 @@ try await sun.$planets.query(on: database).filter(\.$name =~ "M").all()
詳細については [query](query.md) を参照してください。
## Eager Loading {#eager-loading}
## Eager Loading
Fluent のクエリビルダーを使用すると、モデルがデータベースから取得されるときにリレーションを事前に読み込むことができます。これは eager loading と呼ばれ、最初に [`get`](#get) を呼び出す必要なく、リレーションに同期的にアクセスできるようになります。
@ -361,7 +361,7 @@ for planet in planets {
`with` メソッドは、2番目のパラメータとしてオプションのクロージャを受け取ります。このクロージャは、選択されたリレーションの eager load ビルダーを受け取ります。eager loading のネストの深さに制限はありません。
## Lazy Eager Loading {#lazy-eager-loading}
## Lazy Eager Loading
親モデルをすでに取得していて、そのリレーションの1つを読み込みたい場合は、その目的で `get(reload:on:)` メソッドを使用できます。これにより、関連モデルがデータベース(または利用可能な場合はキャッシュ)から取得され、ローカルプロパティとしてアクセスできるようになります。

View File

@ -218,7 +218,7 @@ Fluentはデフォルトでユニーク制約名を生成します。ただし
外部キーアクションはデータベース内でのみ発生し、Fluentをバイパスします。
これは、モデルミドルウェアや論理削除などが正しく動作しない可能性があることを意味します。
## SQL {#sql}
## SQL
`.sql`パラメータを使用すると、スキーマに任意のSQLを追加できます。これは、特定の制約やデータ型を追加するのに役立ちます。
一般的な使用例は、フィールドのデフォルト値を定義することです:
@ -233,7 +233,7 @@ Fluentはデフォルトでユニーク制約名を生成します。ただし
.field("created_at", .datetime, .required, .sql(.default(SQLFunction("now"))))
```
## Dictionary {#dictionary}
## Dictionary
dictionary データ型は、ネストされた辞書値を格納できます。これには、`Codable`に準拠する構造体と、`Codable`値を持つSwift辞書が含まれます。
@ -272,7 +272,7 @@ var pet: Pet
辞書のキーは常に文字列である必要があります。
## Array {#array}
## Array
array データ型は、ネストされた配列を格納できます。これには、`Codable`値を含むSwift配列と、キーなしコンテナを使用する`Codable`型が含まれます。
@ -293,7 +293,7 @@ var tags: [String]
Codable Swiftの`Array`は常に同種の値型を持ちます。異種の値をキーなしコンテナにシリアライズするカスタム`Codable`型は例外であり、`.array`データ型を使用する必要があります。
## Enum {#enum}
## Enum
enum データ型は、文字列ベースのSwift enumをネイティブに格納できます。ネイティブデータベースenumは、データベースに型安全性の追加レイヤーを提供し、生のenumよりもパフォーマンスが高い場合があります。

View File

@ -1,4 +1,4 @@
# フォルダ構造
# フォルダ構造 {#folder-structure}
あなたの初めての Vapor アプリを作成し、ビルドし、実行したので、Vapor のフォルダ構造に慣れるための時間を取りましょう。この構造は、[SPM](spm.ja.md) のフォルダ構造に基づいていますので、以前に SPM を使ったことがあれば、見慣れているはずです。
@ -38,7 +38,7 @@ app.middleware.use(fileMiddleware)
## Sources
このフォルダには、プロジェクトのすべての Swift ソースファイルが含まれています。
トップレベルのフォルダ、`App` は、[SwiftPM](spm.ja.md) のマニフェストで宣言されたパッケージのモジュール反映しています。
トップレベルのフォルダ、`App` は、[SwiftPM](spm.ja.md) のマニフェストで宣言されたパッケージのモジュール反映しています。
### App
@ -56,15 +56,15 @@ Migrations フォルダは、Fluent を使用している場合、データベ
Models フォルダは、`Content` 構造体や Fluent の `Model` を保存するのに適しています。
#### configure.swift
#### configure.swift {#configureswift}
このファイルには、`configure(_:)` 関数が含まれています。このメソッドは、新しく作成された `Application` を設定するために `entrypoint.swift` から呼び出されます。ここで、ルート、データベース、プロバイダなどのサービスの登録をする必要があります。
#### entrypoint.swift
#### entrypoint.swift {#entrypointswift}
このファイルには、Vapor アプリケーションの設定と実行を行うアプリケーションの `@main` エントリーポイントが含まれています。
#### routes.swift
#### routes.swift {#routesswift}
このファイルには、`routes(_:)` 関数が含まれています。このメソッドは、`Application` へのルートを登録するために、`configure(_:)` の終わり近くで呼び出されます。
@ -76,6 +76,6 @@ Models フォルダは、`Content` 構造体や Fluent の `Model` を保存す
このフォルダには、`App` モジュールのコードの単体テストが含まれています。
## Package.swift
## Package.swift {#packageswift}
最後に、[SPM](spm.ja.md) のパッケージマニフェストがあります。

View File

@ -7,7 +7,10 @@
- [Install &rarr; macOS](../install/macos.ja.md)
- [Install &rarr; Linux](../install/linux.ja.md)
## 新規プロジェクト
!!! tip
Vapor ツールボックスで使用されるテンプレートには Swift 6.0 以降が必要です
## 新規プロジェクト {#new-project}
最初のステップは、コンピュータに新しい Vapor プロジェクトを作成することです。ターミナルを開き、ツールボックスの新規プロジェクトコマンドを使用してください。これにより、現在のディレクトリにプロジェクトを含む新しいフォルダが作成されます。
@ -22,8 +25,7 @@ vapor new hello -n
Vapor ツールボックスを使用せずに GitHub [テンプレートリポジトリ](https://github.com/vapor/template-bare)をクローンして最新のテンプレートを取得することもできます。
!!! tip
Vapor and the template now uses `async`/`await` by default.
Vapor テンプレートは、デフォルトで `async`/`await` を使用します。
Vapor とテンプレートは、デフォルトで `async`/`await` を使用します。
macOS 12 にアップデートできない、または `EventLoopFuture` を継続して使用する必要がある場合は、
`--branch macos10-15` フラグを使います。
@ -34,7 +36,7 @@ vapor new hello -n
cd hello
```
## ビルド & 実行
## ビルド & 実行 {#build-run}
### Xcode
@ -58,6 +60,9 @@ Xcode のウィンドウの下部に、コンソールが表示されるはず
Linux やその他 OS (または Xcode を使用したくない場合の macOS も含む)では、 Vim や VScode のようなお好きなエディタでプロジェクトを編集できます。他の IDE の設定に関する最新の詳細は、[Swift Server ガイド](https://github.com/swift-server/guides/blob/main/docs/setup-and-ide-alternatives.md)を参照してください。
!!! tip
VSCode をコードエディタとして使用している場合は、公式の Vapor 拡張機能をインストールすることをお勧めします: [Vapor for VS Code](https://marketplace.visualstudio.com/items?itemName=Vapor.vapor-vscode)
プロジェクトをビルドして実行するには、ターミナルで以下のコマンドを実行します:
```sh
@ -70,7 +75,7 @@ swift run
[ INFO ] Server starting on http://127.0.0.1:8080
```
## Localhost へのアクセス
## Localhost へのアクセス {#visit-localhost}
ウェブブラウザを開き、<a href="http://localhost:8080/hello" target="_blank">localhost:8080/hello</a> または <a href="http://127.0.0.1:8080" target="_blank">http://127.0.0.1:8080</a> にアクセスしてください。

View File

@ -4,9 +4,9 @@
SPM は Cocoapods 、Ruby gems 、 NPM に似ています。SPM は、`swift build` や `swift test` などのコマンドでコマンドラインから使用することも、互換性のある IDE から使用することもできます。しかし、他のパッケージマネージャとは異なり、SPM パッケージのための中央のパッケージインデックスは存在しません。SPM は代わりに、Git リポジトリへの URL を利用し、[Git タグ](https://git-scm.com/book/en/v2/Git-Basics-Tagging)を使用して依存関係のバージョンを管理します。
## パッケージマニフェスト
## パッケージマニフェスト {#package-manifest}
SPM がプロジェクトで最初に探す場所は、パッケージマニフェストです。これは常にプロジェクトのルーディレクトリに配置され、`Package.swift` という名前でなければなりません。
SPM がプロジェクトで最初に探す場所は、パッケージマニフェストです。これは常にプロジェクトのルーディレクトリに配置され、`Package.swift` という名前でなければなりません。
以下は、パッケージマニフェストの例です。
@ -41,7 +41,7 @@ let package = Package(
### Tools Version
パッケージマニフェストの最初の行は、必要な Swift ツールのバージョンを示しています。これは、パッケージがサポートする Swift のバージョン間で Package description API が変更される場合があるため、この行は Swift がマニフェストをどのように解析するかを知らせるために必要ようです。
パッケージマニフェストの最初の行は、必要な Swift ツールのバージョンを示しています。これは、パッケージがサポートする Swift の最小バージョンを指定します。Swift のバージョン間で Package description API が変更される場合があるため、この行は Swift がマニフェストをどのように解析するかを知らせるために必要です。
### Package Name
@ -63,7 +63,7 @@ let package = Package(
ターゲットは、パッケージが含むすべてのモジュール、実行ファイル、テストです。ほとんどの Vapor アプリは 2 つのターゲットを持っていますが、コードを整理するために必要なだけ多くのターゲットを追加することができます。各ターゲットは、それが依存するモジュールを宣言します。コード内でそれらをインポートするためには、ここでモジュールの名前を追加する必要があります。ターゲットは、プロジェクト内の他のターゲットや、[主な依存関係](#dependencies)配列に追加したパッケージで公開されている任意のモジュールに依存することができます。
## フォルダ構造
## フォルダ構造 {#folder-structure}
以下は、SPM パッケージの典型的なフォルダ構造です。
@ -80,7 +80,7 @@ let package = Package(
`.target``.executableTarget` は、`Sources` 内のフォルダに対応しています。
各`.testTarget` は、`Tests` 内のフォルダに対応しています。
## Package.resolved
## Package.resolved {#packageresolved}
プロジェクトを初めてビルドすると、SPM は各依存関係のバージョンを保存する `Package.resolved` ファイルを作成します。次にプロジェクトをビルドするとき、新しいバージョンが利用可能であっても、これらの同じバージョンが使用されます。
@ -88,7 +88,7 @@ let package = Package(
## Xcode
もし、Xocde 11 以降を使用している場合、`Package.swift` ファイルが変更されるたびに、依存関係、ターゲット、プロダクトなどの変更が自動的に行われます。
もし、Xcode 11 以降を使用している場合、`Package.swift` ファイルが変更されるたびに、依存関係、ターゲット、プロダクトなどの変更が自動的に行われます。
最新の依存関係に更新するには、File &rarr; Swift Packages &rarr; Update To Latest Swift Package Versions を使用します。

View File

@ -1,8 +1,8 @@
# Xcode
このページでは、Xcode の仕様に関するいくつかのヒントとテクニックを紹介します。異なる開発環境を使用している場合、このセクションはスキップしてもよいです。
このページでは、Xcode の使用に関するいくつかのヒントとテクニックを紹介します。異なる開発環境を使用している場合、このセクションはスキップしてもよいです。
## カスタムワーキングディレクトリ
## カスタムワーキングディレクトリ {#custom-working-directory}
デフォルトでは、Xcode はあなたのプロジェクトを _DerivedData_ フォルダから実行します。このフォルダは、プロジェクトのルートフォルダ ( _Package.swift_ ファイルがある場所) とは異なります。これは、 Vapor が _.env__Public_ のようなファイルやフォルダを見つけることができないことを意味します。

View File

@ -1,13 +1,13 @@
Vapor ドキュメントへようこそ! Vapor は Swift のWeb フレームワークで、 Swift でバックエンド、ウェブアプリの API HTTP サーバーを書くことができます。 Vapor は Swift で書いており、それは伝統的なサーバー言語よりも多くの利点を提供するモダンで強力で安全な言語です。
Vapor ドキュメントへようこそ! Vapor は Swift の Web フレームワークで、Swift でバックエンド、ウェブアプリの API、HTTP サーバーを書くことができます。 Vapor は Swift で書いており、それは伝統的なサーバー言語よりも多くの利点を提供するモダンで強力で安全な言語です。
## はじめに
## はじめに {#getting-started}
もし、Vapor を使うのが初めてならば、Swift と Vapor をインストールするために[インストール → macOS](install/macos.md)に進んでください。
Vapor をインストールしたら、初めての Vapor アプリを作成するために[はじめに → Hello, world](getting-started/hello-world.md)をチェックしてください!
## その他の情報源
## その他の情報源 {#other-sources}
Vapor に関する情報を見つけるには、他にも素晴らしい場所があります。
@ -20,10 +20,10 @@ Vapor に関する情報を見つけるには、他にも素晴らしい場所
| ソースコード | Vapor の内部での動作を学びます | [visit &rarr;](https://github.com/vapor/vapor) |
| GitHub Issues | GitHub でバグを報告したり、機能をリクエストします | [visit &rarr;](https://github.com/vapor/vapor/issues) |
## 旧ドキュメント
## 旧ドキュメント {#old-documentation}
廃止されたバージョンの Vapor ドキュメントは、[https://legacy.docs.vapor.codes/](https://legacy.docs.vapor.codes/)で見ることができます。
## 著者
## 著者 {#authors}
Vapor コアチーム、および Vapor コミュニティの数百人のメンバー。

View File

@ -1,20 +1,20 @@
# Linux にインストール
# Linux にインストール {#install-on-linux}
Vapor を使うには、Swift 5.9 以上が必要です。これは Swift Server Workgroup が提供する CLI ツール [Swiftly](https://swiftlang.github.io/swiftly/) を使ってインストールできます(推奨)。または、[Swift.org](https://swift.org/download/) で利用可能なツールチェーンを使用してインストールできます。
## サポートされているディストリビューションとバージョン
## サポートされているディストリビューションとバージョン {#supported-distributions-and-versions}
Vapor は、Swift 5.9 またはそれ以上の新しいバージョンがサポートする Linux ディストリビューションと同じバージョンをサポートしています。公式にサポートされているオペレーティングシステムの最新情報については、[公式サポートページ](https://www.swift.org/platform-support/)を参照してください。
公式にはサポートされていない Linux ディストリビューションでも、ソースコードをコンパイルすることで、Swift を実行できるかもしれませんが、Vapor は安定性を保証できません。[Swift repo](https://github.com/apple/swift#getting-started) から Swift のコンパイル方法について詳しく学ぶことができます。
## Swift のインストール
## Swift のインストール {#install-swift}
### Swiftly CLI ツールを使用した自動インストール (推奨)
### Swiftly CLI ツールを使用した自動インストール (推奨) {#automated-installation-using-swiftly-cli-tool-recommended}
Linux で Swiftly と Swift をインストールする手順については、[Swifty のウェブサイト](https://swiftlang.github.io/swiftly/)をご覧ください。その手順に従った後、次のコマンドで Swift をインストールします。
Linux で Swiftly と Swift をインストールする手順については、[Swiftly のウェブサイト](https://swiftlang.github.io/swiftly/)をご覧ください。その手順に従った後、次のコマンドで Swift をインストールします。
#### 基本的な使い方
#### 基本的な使い方 {#basic-usage}
```sh
$ swiftly install latest
@ -31,7 +31,7 @@ Swift version 5.9.1 (swift-5.9.1-RELEASE)
Target: x86_64-unknown-linux-gnu
```
### ツールチェーンを使用した手動インストール
### ツールチェーンを使用した手動インストール {#manual-installation-with-the-toolchain}
Linux 上で Swift をインストールする方法については、Swift.org の[ダウンロードの使用](https://swift.org/download/#using-downloads)を参照してください。
@ -43,17 +43,35 @@ Fedora ユーザーは、以下のコマンドを使用して Swift を簡単に
sudo dnf install swift-lang
```
Fedora 35 を使用している場合、Swift 5.9 またはそれ以降のバージョンを取得するには、EPEL8 を追加する必要があります。
Fedora 35 を使用している場合、Swift 5.9 またはそれ以降のバージョンを取得するには、EPEL 8 を追加する必要があります。
## Docker
Swift の公式Docker イメージも使用できます。これにはコンパイラが事前にインストールされています。[Swift の Docker Hub](https://hub.docker.com/_/swift) で詳しく学ぶことができます。
## ツールボックスのインストール
## ツールボックスのインストール {#install-toolbox}
Swift をインストールしたら、[Vapor Toolbox](https://github.com/vapor/toolbox) をインストールしましょう。この CLI ツールは、Vapor を使用するために必須ではありませんが、役立つユーティリティが含まれています。
Swift をインストールしたら、[Vapor Toolbox](https://github.com/vapor/toolbox) をインストールしましょう。この CLI ツールは、Vapor を使用するために必須ではありませんが、新しい Vapor プロジェクトの作成に役立ちます。
Linux 上では、ソースからツールボックスをビルドする必要があります。GitHub のツールボックスの<a href="https://github.com/vapor/toolbox/releases" target="_blank">リリース</a>で最新バージョンを見つけてください。
### Homebrew
Toolbox は Homebrew 経由で配布されています。まだ Homebrew をお持ちでない場合は、<a href="https://brew.sh" target="_blank">brew.sh</a> でインストール手順をご確認ください。
```sh
brew install vapor
```
インストールが成功したかどうかを確認するためにヘルプを表示します。
```sh
vapor --help
```
利用可能なコマンドのリストが表示されるはずです。
### Makefile
必要に応じて、ソースから Toolbox をビルドすることもできます。GitHub のツールボックスの<a href="https://github.com/vapor/toolbox/releases" target="_blank">リリース</a>で最新バージョンを見つけてください。
```sh
git clone https://github.com/vapor/toolbox.git
@ -70,6 +88,6 @@ vapor --help
利用可能なコマンドのリストが表示されるはずです。
## 次へ
## 次へ {#next}
Swift をインストールしたら、[はじめに &rarr; hello, world](../getting-started/hello-world.md) で初めてのアプリを作成してください。
Swift と Vapor Toolbox をインストールしたら、[はじめに &rarr; Hello, world](../getting-started/hello-world.md) で初めてのアプリを作成してください。

View File

@ -1,8 +1,8 @@
# macOS へのインストール
# macOS へのインストール {#install-on-macos}
Vapor を macOS で使用するには、Swift 5.9 以上が必要です。Swift とそれに関連するすべての依存関係は、Xcode にバンドルされています。
## Xcode のインストール
## Xcode のインストール {#install-xcode}
Mac App Store から[Xcode](https://itunes.apple.com/us/app/xcode/id497799835?mt=12) をインストールします。
@ -26,9 +26,11 @@ Target: arm64-apple-macosx13.0
Vapor 4 は、Swift 5.9 以上が必要です。
## Toolbox のインストール
## Toolbox のインストール {#install-toolbox}
Swift をインストールしたので、次に [Vapor Toolbox](https://github.com/vapor/toolbox) をインストールしましょう。このCLIツールはVapor を使用するためには必須ではありませんが、新しいプロジェクトクリエイーターのような便利なユーティリティが含まれています。
Swift をインストールしたので、次に [Vapor Toolbox](https://github.com/vapor/toolbox) をインストールしましょう。この CLI ツールは Vapor を使用するためには必須ではありませんが、新しい Vapor プロジェクトの作成を支援します。
### Homebrew
Toolbox は Homebrew 経由で配布されています。まだ Homebrew をインストールしていない場合は、<a href="https://brew.sh" target="_blank">brew.sh</a> を参照してインストール手順を確認してください。
@ -44,6 +46,25 @@ vapor --help
利用可能なコマンドのリストが表示されるはずです。
## 次へ
### Makefile
必要に応じて、ソースから Toolbox をビルドすることもできます。GitHub の Toolbox の<a href="https://github.com/vapor/toolbox/releases" target="_blank">リリース</a>で最新バージョンを見つけてください。
```sh
git clone https://github.com/vapor/toolbox.git
cd toolbox
git checkout <desired version>
make install
```
インストールが成功したかどうかを確認するために、ヘルプを表示してください。
```sh
vapor --help
```
利用可能なコマンドのリストが表示されるはずです。
## 次へ {#next}
Swift と Vapor Toolbox をインストールしたので、 [はじめに &rarr; Hello, world](../getting-started/hello-world.md) で初めてのアプリを作成してください。

View File

@ -1,4 +1,4 @@
# カスタムタグ
# カスタムタグ {#custom-tags}
[`LeafTag`](https://api.vapor.codes/leafkit/documentation/leafkit/leaftag) プロトコルを使用して、カスタム Leaf タグを作成することができます。
@ -48,7 +48,7 @@ struct NowTag: LeafTag {
}
```
## タグの設定
## タグの設定 {#configure-tag}
`NowTag` を実装したので、Leaf にそれを伝えるだけです。このようにして、たとえ別のパッケージで定義されたタグでも追加することができます。通常、これを `configure.swift` で行います:
@ -62,18 +62,18 @@ app.leaf.tags["now"] = NowTag()
The time is #now()
```
## コンテキストプロパティ
## コンテキストプロパティ {#context-properties}
`LeafContext` には、重要なプロパティが 2 つあります。それが `parameters``data` です。この 2 つで必要な情報はすべて揃っています。
- `parameters`: タグのパラメータを含む配列です
- `data`: コンテキストとして `render(_:_:)` に渡されたビューのデータを含む辞書です
### Hello タグによる実例
### Hello タグによる実例 {#example-hello-tag}
これを理解するために、両方のプロパティを使ったシンプルな hello タグを実装してみましょう。
#### parameters の使用
#### parameters の使用 {#using-parameters}
nameの値が提供される、1つ目のパラメータにアクセスできます
@ -97,7 +97,7 @@ struct HelloTag: UnsafeUnescapedLeafTag {
#hello("John")
```
#### data の使用
#### data の使用 {#using-data}
data プロパティの中の "name" キーを使って名前の値にアクセスします。

View File

@ -29,7 +29,7 @@ let package = Package(
)
```
## 設定
## 設定 {#configure}
パッケージをプロジェクトに追加したら、Vapor を設定してそれを使用するように構成します。これは通常、[`configure.swift`](../getting-started/folder-structure.md#configureswift) で行います。
@ -41,12 +41,22 @@ app.views.use(.leaf)
これにより、コード内で `req.view` を呼び出すと、Vapor が `LeafRenderer` を使用するように指示します。
!!! note
Leaf には、ページをレンダリングするための内部キャッシュがあります。`Application` の環境が `.development` に設定されている場合、このキャッシュは無効になり、テンプレートへの変更が即座に反映されます。`.production` やその他の環境では、キャッシュがデフォルトで有効になっており、テンプレートに加えた変更はアプリケーションを再起動するまで反映されません。
!!! warning
Xcode から実行する際に Leaf がテンプレートを見つけられるようにするためには、 Xcode ワークスペースの [custom working directory](../getting-started/xcode.md#_1) を設定する必要があります。
## フォルダ構成
Xcode から実行する際に Leaf がテンプレートを見つけられるようにするためには、 Xcode ワークスペースの [custom working directory](../getting-started/xcode.md#custom-working-directory) を設定する必要があります。
### ページレンダリング用のキャッシュ {#cache-for-rendering-pages}
Leaf には、ページをレンダリングするための内部キャッシュがあります。`Application` の環境が `.development` に設定されている場合、このキャッシュは無効になり、テンプレートへの変更が即座に反映されます。`.production` やその他の環境では、キャッシュがデフォルトで有効になっており、テンプレートに加えた変更はアプリケーションを再起動するまで反映されません。
Leaf のキャッシュを無効にするには、以下を実行します:
```swift
app.leaf.cache.isEnabled = false
```
!!! warning
キャッシュを無効にすることはデバッグには役立ちますが、リクエストごとにテンプレートを再コンパイルする必要があるため、パフォーマンスに大きな影響を与える可能性があるため、本番環境では推奨されません。
## フォルダ構成 {#folder-structure}
Leaf を設定したら、`.leaf` ファイルを格納するための `Views` フォルダを用意する必要があります。デフォルトでは、Leaf はプロジェクトのルートに対して `./Resources/Views` というフォルダを要求します。
@ -65,7 +75,7 @@ VaporApp
   └── ...
```
## Viewのレンダリング
## Viewのレンダリング {#rendering-a-view}
Leaf が設定できたので、最初のテンプレートをレンダリングしてみましょう。`Resources/Views` フォルダ内に、次の内容で `hello.leaf` という新しいファイルを作成します。

View File

@ -1,10 +1,10 @@
# Leaf 概要
# Leaf 概要 {#leaf-overview}
Leaf は、Swift にインスパイアされた構文を持つ強力なテンプレート言語です。これを使って、フロントエンドのウェブサイト向けに動的な HTML ページを生成したり、API から送信するリッチなメールを生成したりできます。
このガイドでは、Leaf の構文と使用可能なタグについての概要を説明します。
## テンプレート構文
## テンプレート構文 {#template-syntax}
ここに、基本的な Leaf タグの使用例を示します。
@ -53,7 +53,7 @@ Leaf は、Swift でお馴染みの多くの式もサポートしています。
## Context
[Getting Started](getting-started.ja.md) の例では、 `[String: String]` 辞書を使って Leaf にデータを渡しましたが、`Encodable` に準拠する任意のデータを渡すことができます。実際、`[String: Any]` はサポートされていないため、`Encodable` な構造体を使用する方が推奨されます。つまり、配列を直接渡すことは*できず*、代わりに構造体にラップする必要があります:
[Getting Started](getting-started.md) の例では、 `[String: String]` 辞書を使って Leaf にデータを渡しましたが、`Encodable` に準拠する任意のデータを渡すことができます。実際、`[String: Any]` はサポートされていないため、`Encodable` な構造体を使用する方が推奨されます。つまり、配列を直接渡すことは*できず*、代わりに構造体にラップする必要があります:
```swift
struct WelcomeContext: Encodable {
@ -72,11 +72,11 @@ return req.view.render("home", WelcomeContext(title: "Hello!", numbers: [42, 900
#endfor
```
## 使用例
## 使用例 {#usage}
以下は、Leaf の一般的な使用例です。
### 条件
### 条件 {#conditions}
Leaf は、`#if` タグを使用してさまざまな条件を評価できます。例えば、変数を提供すると、その変数がコンテキストに存在するかチェックします:
@ -120,7 +120,7 @@ Leaf は、`#if` タグを使用してさまざまな条件を評価できます
#endif
```
### ループ
### ループ {#loops}
アイテムの配列を提供すると、Leaf はそれをループし、 `#for` タグを使用して各アイテムを個別に操作できます。
@ -154,9 +154,9 @@ Planets:
- Mars
```
### テンプレートの拡張
### テンプレートの拡張 {#extending-templates}
Leaf の `#extend` タグを使用すると、あるテンプレートの内容を別のテンプレートにコピーすることができます。このタグを使用する場合、テンプレートファイルの拡張子 .leaf を省略することが奨励されます。
Leaf の `#extend` タグを使用すると、あるテンプレートの内容を別のテンプレートにコピーすることができます。このタグを使用する場合、テンプレートファイルの拡張子 .leaf を常に省略する必要があります。
拡張は、複数のページで共有される標準的なコンテンツ、例えばフッターや広告コード、テーブルなどをコピーするのに便利です:
@ -164,9 +164,9 @@ Leaf の `#extend` タグを使用すると、あるテンプレートの内容
#extend("footer")
```
このタグは、あるテンプレートを別のテンプレートの上に構築する場合にも便利です。例えば、レイアウト用の layout.leaf ファイルを作成し、ウェブサイトの HTML 構造、CSS、JavaScript など、ページごとに異なるコンテンツを配置する場所を開けておくことができます。
このタグは、あるテンプレートを別のテンプレートの上に構築する場合にも便利です。例えば、レイアウト用の layout.leaf ファイルを作成し、ウェブサイトのレイアウトに必要なすべてのコードHTML 構造、CSS、JavaScriptを含め、ページごとに異なるコンテンツを配置する場所を空けておくことができます。
この方法を使用すると、独自のコンテンツを入力し、それを適切に配置する親テンプレートを拡張する子テンプレートを構築することができます。このため、`#export` および `#import` タグを使用して、コンテンツをコンテキストに保存し、後でそれを取得することができます。
この方法を使用すると、独自のコンテンツを入力し、それを適切に配置する親テンプレートを拡張する子テンプレートを構築することができます。このため、`#export` および `#import` タグを使用して、コンテキストにコンテンツを保存し、後でそれを取得することができます。
例えば、次のような `child.leaf` テンプレートを作成できます:
@ -200,7 +200,7 @@ Leaf の `#extend` タグを使用すると、あるテンプレートの内容
</html>
```
### その他のタグ
### その他のタグ {#other-tags}
#### `#count`
@ -283,7 +283,7 @@ The time is #unsafeHTML(styledTitle)
#### `#dumpContext`
`dumpContext` タグは、コンテキスト全体を人間が読める形式でレンダリングします。このタグを使用して、現在のレンダリングに提供されているコンテキストをデバッグします。
`#dumpContext` タグは、コンテキスト全体を人間が読める形式でレンダリングします。このタグを使用して、現在のレンダリングに提供されているコンテキストをデバッグします。
```leaf
Hello, world!

View File

@ -37,7 +37,7 @@ struct CustomRedisSessionsDelegate: RedisSessionsDelegate {
app.sessions.use(.redis(delegate: CustomRedisSessionsDelegate()))
```
## RedisSessionsDelegate {#redissessionsdelegate}
## RedisSessionsDelegate
> APIドキュメント[`RedisSessionsDelegate`](https://api.vapor.codes/redis/documentation/redis/redissessionsdelegate)

View File

@ -17,7 +17,7 @@ VaporのAuthentication APIは、[Basic](https://tools.ietf.org/html/rfc7617)お
認証が成功した場合、オーセンティケータは検証されたユーザーを`req.auth`に追加します。このユーザーは、オーセンティケータによって保護されているルートで`req.auth.get(_:)`を使用してアクセスできます。認証が失敗した場合、ユーザーは`req.auth`に追加されず、アクセスしようとしても失敗します。
## Authenticatable {#authenticatable}
## Authenticatable
Authentication APIを使用するには、まず`Authenticatable`に準拠するユーザータイプが必要です。これは`struct`、`class`、またはFluentの`Model`でも構いません。以下の例では、`name`という1つのプロパティを持つシンプルな`User`構造体を想定しています。
@ -55,7 +55,7 @@ let protected = app.grouped(UserAuthenticator())
認証の要求は、オーセンティケータの構成を可能にするため、オーセンティケータミドルウェアによって行われません。[構成](#composition)の詳細については以下をお読みください。
## Basic {#basic}
## Basic
Basic認証は、`Authorization`ヘッダーでユーザー名とパスワードを送信します。ユーザー名とパスワードはコロン(例:`test:secret`で連結され、base-64エンコードされ、`"Basic "`でプレフィックスされます。次の例のリクエストは、ユーザー名`test`とパスワード`secret`をエンコードしています。
@ -116,7 +116,7 @@ struct UserAuthenticator: AsyncBasicAuthenticator {
このオーセンティケータをアプリに追加し、上記で定義したルートをテストすると、ログインが成功した場合に名前`"Vapor"`が返されるはずです。認証情報が正しくない場合は、`401 Unauthorized`エラーが表示されるはずです。
## Bearer {#bearer}
## Bearer
Bearer認証は、`Authorization`ヘッダーでトークンを送信します。トークンには`"Bearer "`がプレフィックスされます。次の例のリクエストはトークン`foo`を送信しています。
@ -252,7 +252,7 @@ print(user?.name) // String?
req.auth.logout(User.self)
```
## Fluent {#fluent}
## Fluent
[Fluent](../fluent/overview.md)は、既存のモデルに追加できる`ModelAuthenticatable`と`ModelTokenAuthenticatable`の2つのプロトコルを定義しています。モデルをこれらのプロトコルに準拠させることで、エンドポイントを保護するためのオーセンティケータを作成できます。
@ -395,7 +395,7 @@ Content-Type: application/json
}
```
#### Model Authenticatable {#model-authenticatable}
#### Model Authenticatable
これで、ユーザーモデルと新しいユーザーを作成するためのエンドポイントができたので、モデルを`ModelAuthenticatable`に準拠させましょう。これにより、モデルをユーザー名とパスワードを使用して認証できるようになります。
@ -539,7 +539,7 @@ passwordProtected.post("login") { req async throws -> UserToken in
後で使用するので、取得したトークンを保持してください。
#### Model Token Authenticatable {#model-token-authenticatable}
#### Model Token Authenticatable
`UserToken`を`ModelTokenAuthenticatable`に準拠させます。これにより、トークンが`User`モデルを認証できるようになります。
@ -589,7 +589,7 @@ Vaporの[Session API](../advanced/sessions.md)を使用して、リクエスト
セッションは、Webブラウザに直接HTMLを提供するVaporで構築されたフロントエンドWebアプリケーションに最適です。APIの場合、リクエスト間でユーザーデータを永続化するために、ステートレスなトークンベースの認証を使用することをお勧めします。
### Session Authenticatable {#session-authenticatable}
### Session Authenticatable
セッションベースの認証を使用するには、`SessionAuthenticatable`に準拠するタイプが必要です。この例では、シンプルな構造体を使用します。
@ -698,7 +698,7 @@ cookie: vapor_session=123
今回は、`UserSessionAuthenticator`がユーザーを認証し、再びユーザーのメールが返されるはずです。
### Model Session Authenticatable {#model-session-authenticatable}
### Model Session Authenticatable
Fluentモデルは、`ModelSessionAuthenticatable`に準拠することで`SessionAuthenticator`を生成できます。これは、モデルの一意の識別子をセッション識別子として使用し、セッションからモデルを復元するためのデータベース検索を自動的に実行します。
@ -811,7 +811,7 @@ credentialsProtectedRoute.post("login", use: loginPostHandler)
`CredentialsAuthenticator`は、リクエストボディから`username`と`password`を抽出し、ユーザー名からユーザーを見つけ、パスワードを検証します。パスワードが有効な場合、ミドルウェアはリクエストを認証します。その後、`SessionAuthenticator`が後続のリクエストのためにセッションを認証します。
## JWT {#jwt}
## JWT
[JWT](jwt.md)は、着信リクエストでJSON Web Tokenを認証するために使用できる`JWTAuthenticator`を提供します。JWTを初めて使用する場合は、[概要](jwt.md)を確認してください。

View File

@ -2,7 +2,7 @@
Vapor には [SwiftCrypto](https://github.com/apple/swift-crypto/) が含まれており、これは Apple の CryptoKit ライブラリの Linux 互換ポートです。SwiftCrypto がまだサポートしていない [Bcrypt](https://ja.wikipedia.org/wiki/Bcrypt) や [TOTP](https://ja.wikipedia.org/wiki/Time-based_One-time_Password) のような追加の暗号 API も公開されています。
## SwiftCrypto {#swiftcrypto}
## SwiftCrypto
Swift の `Crypto` ライブラリは Apple の CryptoKit API を実装しています。そのため、[CryptoKit ドキュメント](https://developer.apple.com/documentation/cryptokit) と [WWDC トーク](https://developer.apple.com/videos/play/wwdc2019/709) は API を学ぶための優れたリソースです。
@ -23,7 +23,7 @@ CryptoKit には以下のサポートが含まれています:
- 公開鍵暗号:`Curve25519`、`P521`、`P384`、`P256`
- 安全でないハッシュ化:`SHA1`、`MD5`
## Bcrypt {#bcrypt}
## Bcrypt
Bcrypt はランダム化されたソルトを使用して、同じパスワードを複数回ハッシュ化しても同じダイジェストにならないようにするパスワードハッシュアルゴリズムです。
@ -50,11 +50,11 @@ if pass {
Bcrypt パスワードでのログインは、まずメールアドレスまたはユーザー名でデータベースからユーザーのパスワードダイジェストを取得することで実装できます。その後、既知のダイジェストを提供された平文パスワードに対して検証できます。
## OTP {#otp}
## OTP
Vapor は HOTP と TOTP の両方のワンタイムパスワードをサポートしています。OTP は SHA-1、SHA-256、SHA-512 ハッシュ関数で動作し、6 桁、7 桁、または 8 桁の出力を提供できます。OTP は、単一使用の人間が読めるパスワードを生成することで認証を提供します。これを行うために、両当事者はまず対称鍵に合意し、生成されたパスワードのセキュリティを維持するために常に秘密にしておく必要があります。
#### HOTP {#hotp}
#### HOTP
HOTP は HMAC 署名に基づく OTP です。対称鍵に加えて、両当事者はパスワードの一意性を提供する数値であるカウンターにも合意します。各生成試行後、カウンターは増加します。
@ -67,7 +67,7 @@ let code = hotp.generate(counter: 25)
HOTP.generate(key: key, digest: .sha256, digits: .six, counter: 25)
```
#### TOTP {#totp}
#### TOTP
TOTP は HOTP の時間ベースのバリエーションです。ほとんど同じように動作しますが、単純なカウンターの代わりに、現在の時刻を使用して一意性を生成します。非同期クロック、ネットワーク遅延、ユーザーの遅延、およびその他の混乱要因によって導入される避けられないずれを補償するために、生成された TOTP コードは指定された時間間隔(最も一般的には 30 秒)にわたって有効のままです。

View File

@ -84,4 +84,4 @@ req.password.async.verify("vapor", created: digest).map { bool in
let result = try await req.password.async.verify("vapor", created: digest)
```
バックグラウンドスレッドでハッシュを計算することで、アプリケーションのイベントループを解放し、より多くの受信リクエストを処理できるようになります。
バックグラウンドスレッドでハッシュを計算することで、アプリケーションのイベントループを解放し、より多くの受信リクエストを処理できるようになります。

View File

@ -1,4 +1,4 @@
# 4.0へのアップグレード {#upgrading-to-4.0}
# 4.0へのアップグレード {#upgrading-to-40}
このガイドでは、既存のVapor 3.xプロジェクトを4.xにアップグレードする方法を説明します。このガイドでは、Vaporの公式パッケージに加え、よく使用されるプロバイダーについても網羅します。不足している内容があれば、[Vaporのチームチャット](https://discord.gg/vapor)で質問するのがおすすめです。IssuesやPull Requestも歓迎です。
@ -8,7 +8,7 @@ Vapor 4を使用するには、Xcode 11.4およびmacOS 10.15以上が必要で
ドキュメントのインストールセクションで依存関係のインストールについて説明しています。
## Package.swift
## Package.swift {#packageswift}
Vapor 4へのアップグレードの最初のステップは、パッケージの依存関係を更新することです。以下は更新されたPackage.swiftファイルの例です。更新された[テンプレートPackage.swift](https://github.com/vapor/template/blob/main/Package.swift)も確認できます。
@ -130,7 +130,7 @@ try app.run()
基本的なAppモジュール構造の更新方法を見てみましょう。
### configure.swift
### configure.swift {#configureswift}
`configure`メソッドは`Application`のインスタンスを受け入れるように変更する必要があります。
@ -162,11 +162,11 @@ public func configure(_ app: Application) throws {
ルーティング、ミドルウェア、Fluentなどの設定に関する構文の変更は以下で説明します。
### boot.swift
### boot.swift {#bootswift}
`boot`の内容は、アプリケーションインスタンスを受け入れるようになったため、`configure`メソッドに配置できます。
### routes.swift
### routes.swift {#routesswift}
`routes`メソッドは`Application`のインスタンスを受け入れるように変更する必要があります。