/
Content.swift
125 lines (113 loc) 路 3.56 KB
/
Content.swift
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
/// Convertible to / from content in an HTTP message.
///
/// Conformance to this protocol consists of:
///
/// - `Codable`
/// - `RequestDecodable`
/// - `ResponseEncodable`
///
/// If adding conformance in an extension, you must ensure the type already conforms to `Codable`.
///
/// struct Hello: Content {
/// let message = "Hello!"
/// }
///
/// router.get("greeting") { req in
/// return Hello() // {"message":"Hello!"}
/// }
///
public protocol Content: Codable, RequestDecodable, ResponseEncodable {
/// The default `MediaType` to use when _encoding_ content. This can always be overridden at the encode call.
///
/// Default implementation is `MediaType.json` for all types.
///
/// struct Hello: Content {
/// static let defaultContentType = .urlEncodedForm
/// let message = "Hello!"
/// }
///
/// router.get("greeting") { req in
/// return Hello() // message=Hello!
/// }
///
/// router.get("greeting2") { req in
/// let res = req.response()
/// try res.content.encode(Hello(), as: .json)
/// return res // {"message":"Hello!"}
/// }
///
static var defaultContentType: HTTPMediaType { get }
mutating func beforeEncode() throws
mutating func afterDecode() throws
}
/// MARK: Default Implementations
extension Content {
/// Default implementation is `MediaType.json` for all types.
///
/// See `Content`.
public static var defaultContentType: HTTPMediaType {
return .json
}
public static func decodeRequest(_ request: Request) -> EventLoopFuture<Self> {
do {
let content = try request.content.decode(Self.self)
return request.eventLoop.makeSucceededFuture(content)
} catch {
return request.eventLoop.makeFailedFuture(error)
}
}
public func encodeResponse(for request: Request) -> EventLoopFuture<Response> {
let response = Response()
do {
try response.content.encode(self)
} catch {
return request.eventLoop.makeFailedFuture(error)
}
return request.eventLoop.makeSucceededFuture(response)
}
public mutating func beforeEncode() throws { }
public mutating func afterDecode() throws { }
}
// MARK: Default Conformances
extension String: Content {
/// See `Content`.
public static var defaultContentType: HTTPMediaType {
return .plainText
}
}
extension FixedWidthInteger where Self: Content {
/// See `Content`.
public static var defaultContentType: HTTPMediaType {
return .plainText
}
}
extension Int: Content { }
extension Int8: Content { }
extension Int16: Content { }
extension Int32: Content { }
extension Int64: Content { }
extension UInt: Content { }
extension UInt8: Content { }
extension UInt16: Content { }
extension UInt32: Content { }
extension UInt64: Content { }
extension BinaryFloatingPoint where Self: Content {
/// See `Content`.
public static var defaultContentType: HTTPMediaType {
return .plainText
}
}
extension Double: Content { }
extension Float: Content { }
extension Array: Content, ResponseEncodable, RequestDecodable where Element: Content {
/// See `Content`.
public static var defaultContentType: HTTPMediaType {
return .json
}
}
extension Dictionary: Content, ResponseEncodable, RequestDecodable where Key == String, Value: Content {
/// See `Content`.
public static var defaultContentType: HTTPMediaType {
return .json
}
}