-
-
Notifications
You must be signed in to change notification settings - Fork 332
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add Japanese translation for ”basic" (#948)
## 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
1 parent
f437e4a
commit 40a7eea
Showing
10 changed files
with
2,039 additions
and
1 deletion.
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | ||
``` | ||
|
||
初めてデフォルトクライアントを使用する前に、必ず設定を完了させておく必要があります。 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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> | ||
""") | ||
} | ||
``` |
Oops, something went wrong.