Skip to content

Commit

Permalink
Add Japanese translation for ”basic" (#948)
Browse files Browse the repository at this point in the history
## Added Content

Added a Japanese translation of
[basics](https://github.com/vapor/docs/tree/main/docs/basics).

Also addressed Issue.:
[fb3b0c2](fb3b0c2)

<details>
<summary>Japanese</summary>
## 追加内容

[basics](https://github.com/vapor/docs/tree/main/docs/basics)
の日本語訳を追加しました。
</details>
  • Loading branch information
KaitoMuraoka committed Nov 22, 2023
1 parent f437e4a commit 40a7eea
Show file tree
Hide file tree
Showing 10 changed files with 2,039 additions and 1 deletion.
431 changes: 431 additions & 0 deletions docs/basics/async.ja.md

Large diffs are not rendered by default.

74 changes: 74 additions & 0 deletions docs/basics/client.ja.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
# クライアント

Vapor のクライアント API では、外部のリソースに対して HTTP 通信を行うことができます。これは [async-http-client](https://github.com/swift-server/async-http-client) に基づいており、[コンテンツ](content.ja.md) API と統合されています。

## 概要

`Application` やルートハンドラー内の `Request` から、デフォルトクライアントにアクセスできます。

```swift
app.client // Client

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

アプリケーションのクライアントは、設定時に HTTP リクエストを送る際に便利です。ルートハンドラー内で HTTP リクエストを行う場合は、リクエストに紐づくクライアントを使うべきです。

### メソッド

`GET` リクエストを行う際には、目的の URL を `get` メソッドに渡します。

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

`get``post``delete` など、各種 HTTP メソッドに対応したメソッドがあります。クライアントからのレスポンスは将来的に返され、HTTPステータス、ヘッダー、ボディが含まれます。

### コンテンツ

Vapor の [コンテンツ](content.ja.md) を使うと、クライアントリクエストやレスポンスのデータを扱うことができます。コンテンツやクエリパラメータをエンコードしたり、ヘッダーを追加するには、`beforeSend` クロージャを使います。

```swift
let response = try await req.client.post("https://httpbin.org/status/200") { req in
// リクエストURLにクエリ文字列をエンコードします。
try req.query.encode(["q": "test"])

// JSONをリクエストボディにエンコードします。
try req.content.encode(["hello": "world"])

// リクエストに認証ヘッダーを追加します。
let auth = BasicAuthorization(username: "something", password: "somethingelse")
req.headers.basicAuthorization = auth
}
//レスポンスを扱う
```

レスポンスボディを `Content` を使ってデコードすることもできます。:

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

もし、futures を使っている場合は、`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
}
```

## 設定

アプリケーションを通じて、基本となる HTTP クライアントを設定することができます。

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

初めてデフォルトクライアントを使用する前に、必ず設定を完了させておく必要があります。
283 changes: 283 additions & 0 deletions docs/basics/content.ja.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,283 @@
# コンテンツ

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 コンテンツタイプに対するエンコーディングの戦略を追加したり、変更したり、置き換えたりすることができます。

## 概要

Vapor のコンテンツ API の仕組みを理解するためには、HTTP メッセージの基本について知っておく必要があります。以下にリクエストの例を示します。

```http
POST /greeting HTTP/1.1
content-type: application/json
content-length: 18
{"hello": "world"}
```

このリクエストは、`content-type` ヘッダーを通じて `application/json` メディアタイプでJSON形式のデータが含まれていることを示しています。ヘッダーの後のボディ部分には、約束されたJSONデータが続きます。

### コンテンツ構造体

この HTTP メッセージをデコードする最初のステップは、期待される構造にマッチする Codable 型を作成することです。

```swift
struct Greeting: Content {
var hello: String
}
```

型を `Content` に準拠させると、コンテンツ API を扱うための追加ユーティリティが得られると同時に、`Codable` にも自動的に準拠するようになります。


コンテンツの構造ができたら、`req.content` を使ってリクエストからデコードできます。

```swift
app.post("greeting") { req in
let greeting = try req.content.decode(Greeting.self)
print(greeting.hello) // "world"
return HTTPStatus.ok
}
```

このデコードメソッドは、リクエストのコンテンツタイプに基づいて適切なデコーダーを見つけます。デコーダーが見つからない、またはリクエストにコンテンツタイプヘッダーが含まれていない場合、`415` エラーが発生します。

つまり、このルートは URL エンコードされたフォームなど、他のサポートされているコンテンツタイプも自動的に受け入れるということです。

```http
POST /greeting HTTP/1.1
content-type: application/x-www-form-urlencoded
content-length: 11
hello=world
```

ファイルアップロードのケースでは、コンテンツのプロパティは `Data` 型である必要があります。

```swift
struct Profile: Content {
var name: String
var email: String
var image: Data
}
```

### サポートされるメディアタイプ

以下は、コンテンツ API がデフォルトでサポートしているメディアタイプです。

|name|header value|media type|
|-|-|-|
|JSON|application/json|`.json`|
|Multipart|multipart/form-data|`.formData`|
|URL-Encoded Form|application/x-www-form-urlencoded|`.urlEncodedForm`|
|Plaintext|text/plain|`.plainText`|
|HTML|text/html|`.html`|

すべてのメディアタイプが全ての `Codable` 機能をサポートしているわけではありません。例えば、JSON はトップレベルのフラグメントをサポートしておらず、プレーンテキストはネストされたデータをサポートしていません。

## クエリ

Vapor のコンテンツ API は、URL のクエリ文字列にエンコードされたデータの処理に対応しています。

### デコード

URL クエリ文字列をデコードする方法を理解するために、以下の例をご覧ください。

```http
GET /hello?name=Vapor HTTP/1.1
content-length: 0
```

HTTP メッセージのボディ内容を扱う API と同様に、URL クエリ文字列を解析する最初のステップは、期待される構造にあった `struct` を作成することです。

```swift
struct Hello: Content {
var name: String?
}
```

`name` がオプションな `String` であることに注意して下さい。URL クエリ文字列は常にオプショナルであるべきだからです。パラメーターを必須にしたい場合は、ルートパラメーターを使って下さい。

期待されるクエリ文字列に合わせた `Content` 構造体が用意できたら、それをデコードできます。

```swift
app.get("hello") { req -> String in
let hello = try req.query.decode(Hello.self)
return "Hello, \(hello.name ?? "Anonymous")"
}
```

上記の例のリクエストに基づいて、このルートは次のような応答を返します:

```http
HTTP/1.1 200 OK
content-length: 12
Hello, Vapor
```

例えば、次のリクエストのようにクエリ文字列が省略された場合は、"Anonymous" が使われます。

```http
GET /hello HTTP/1.1
content-length: 0
```

### 単一の値

`Content` 構造体へのデコードだけでなく、Vapor はクエリ文字列から単一の値を取得することもサポートしています。これはサブスクリプトを使用して行われます。

```swift
let name: String? = req.query["name"]
```

## フック

Vapor は、`Content` タイプに対して `beforeEncode` および `afterDecode` を自動的に呼び出します。デフォルトの実装は何もしませんが、これらのメソッドを使用してカスタムロジックを実行することができます。

```swift
// この 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` は構造体のみに必要で、クラスには必要ありません。
mutating func beforeEncode() throws {
// 名前は渡されないことがありますが、渡される場合は空文字列であってはなりません。
guard
let name = self.name?.trimmingCharacters(in: .whitespacesAndNewlines),
!name.isEmpty
else {
throw Abort(.badRequest, reason: "Name must not be empty.")
}
self.name = name
}
```

## デフォルトの上書き

Vapor の Content API によって使用されるデフォルトのエンコーダーとデコーダーは設定可能です。

### グローバル

`ContentConfiguration.global` を使用すると、Vapor がデフォルトで使用するエンコーダーやデコーダーを変更できます。これは、アプリケーション全体でデータの解析やシリアライズ方法を変更するのに便利です。

```swift
// UNIX タイムスタンプの日付を使用する新しい JSON エンコーダーを作成します。
let encoder = JSONEncoder()
encoder.dateEncodingStrategy = .secondsSince1970

// `.json` メディアタイプで使用されるグローバルエンコーダーを上書きします。
ContentConfiguration.global.use(encoder: encoder, for: .json)
```

`ContentConfiguration` の変更は通常、`configure.swift` で行われます。

### 1回限り

`req.content.decode` のようなエンコーディングやデコーディングのメソッド呼び出しは、1回限りの使用のためにカスタムコーダーを渡すことをサポートしています。

```swift
// UNIX タイムスタンプの日付を使用する新しい JSON デコーダーを作成します。
let decoder = JSONDecoder()
decoder.dateDecodingStrategy = .secondsSince1970

// カスタムデコーダーを使用して Hello 構造体をデコードします。
let hello = try req.content.decode(Hello.self, using: decoder)
```

## カスタムコーダー

アプリケーションやサードパーティのパッケージは、Vapor がデフォルトでサポートしていないメディアタイプに対応するためにカスタムコーダーを作成することができます。

### Content

Vapor は、HTTP メッセージボディのコンテンツを処理するためのコーダーのために、`ContentDecoder``ContentEncoder` の2つのプロトコルを指定しています。

```swift
public protocol ContentEncoder {
func encode<E>(_ encodable: E, to body: inout ByteBuffer, headers: inout HTTPHeaders) throws
where E: Encodable
}

public protocol ContentDecoder {
func decode<D>(_ decodable: D.Type, from body: ByteBuffer, headers: HTTPHeaders) throws -> D
where D: Decodable
}
```

これらのプロトコルに準拠することで、カスタムコーダーを上記で指定されたように `ContentConfiguration` に登録できます。

### URL クエリ

Vapor は、URL クエリ文字列のコンテンツを処理することができる coder のための 2 つのプロトコルを指定しています: `URLQueryDecoder``URLQueryEncoder`

```swift
public protocol URLQueryDecoder {
func decode<D>(_ decodable: D.Type, from url: URI) throws -> D
where D: Decodable
}

public protocol URLQueryEncoder {
func encode<E>(_ encodable: E, to url: inout URI) throws
where E: Encodable
}
```

これらのプロトコルに準拠することで、`use(urlEncoder:)` および `use(urlDecoder:)` メソッドを使用して、URL クエリ文字列の処理のためにカスタムコーダーを `ContentConfiguration` に登録できます。

### カスタム `ResponseEncodable`

別のアプローチには、タイプに `ResponseEncodable` を実装するというものがあります。この単純な `HTML` ラッパータイプを考えてみてください。

```swift
struct HTML {
let value: String
}
```

その `ResponseEncodable` の実装は以下のようになります。

```swift
extension HTML: ResponseEncodable {
public func encodeResponse(for request: Request) -> EventLoopFuture<Response> {
var headers = HTTPHeaders()
headers.add(name: .contentType, value: "text/html")
return request.eventLoop.makeSucceededFuture(.init(
status: .ok, headers: headers, body: .init(string: value)
))
}
}
```

`async`/`await` を使用している場合は、`AsyncResponseEncodable` を使用できます。

```swift
extension HTML: AsyncResponseEncodable {
public func encodeResponse(for request: Request) async throws -> Response {
var headers = HTTPHeaders()
headers.add(name: .contentType, value: "text/html")
return .init(status: .ok, headers: headers, body: .init(string: value))
}
}
```

これにより、`Content-Type` ヘッダーをカスタマイズできることに注意して下さい。詳細は [`HTTPHeaders` リファレンス](https://api.vapor.codes/vapor/documentation/vapor/response/headers) を参照して下さい。

その後、ルート内でレスポンスタイプとして `HTML` を使用できます。

```swift
app.get { _ in
HTML(value: """
<html>
<body>
<h1>Hello, World!</h1>
</body>
</html>
""")
}
```

0 comments on commit 40a7eea

Please sign in to comment.