14
14
15
15
import Foundation
16
16
import OpenAPIRuntime
17
+ import HTTPTypes
17
18
import Vapor
18
19
import NIOFoundationCompat
19
20
@@ -31,24 +32,24 @@ public final class VaporTransport {
31
32
32
33
extension VaporTransport : ServerTransport {
33
34
public func register(
34
- _ handler: @Sendable @escaping ( OpenAPIRuntime . Request , OpenAPIRuntime . ServerRequestMetadata )
35
- async throws -> OpenAPIRuntime . Response ,
36
- method : OpenAPIRuntime . HTTPMethod ,
37
- path : [ RouterPathComponent ] ,
38
- queryItemNames : Set < String >
35
+ _ handler: @Sendable @escaping (
36
+ HTTPTypes . HTTPRequest , OpenAPIRuntime . HTTPBody ? , OpenAPIRuntime . ServerRequestMetadata
37
+ ) async throws -> ( HTTPTypes . HTTPResponse , OpenAPIRuntime . HTTPBody ? ) ,
38
+ method : HTTPRequest . Method ,
39
+ path : String
39
40
) throws {
40
41
self . routesBuilder. on (
41
42
HTTPMethod ( method) ,
42
- path . map ( Vapor . PathComponent. init ( _ : ) )
43
+ [ PathComponent] ( path )
43
44
) { vaporRequest in
44
- let request = try await OpenAPIRuntime . Request ( vaporRequest)
45
+ let request = try HTTPTypes . HTTPRequest ( vaporRequest)
46
+ let body = OpenAPIRuntime . HTTPBody ( vaporRequest)
45
47
let requestMetadata = try OpenAPIRuntime . ServerRequestMetadata (
46
48
from: vaporRequest,
47
- forPath: path,
48
- extractingQueryItemNamed: queryItemNames
49
+ forPath: path
49
50
)
50
- let response = try await handler ( request, requestMetadata)
51
- return Vapor . Response ( response)
51
+ let response = try await handler ( request, body , requestMetadata)
52
+ return Vapor . Response ( response: response . 0 , body : response . 1 )
52
53
}
53
54
}
54
55
}
@@ -59,56 +60,65 @@ enum VaporTransportError: Error {
59
60
case missingRequiredPathParameter( String )
60
61
}
61
62
62
- extension Vapor . PathComponent {
63
- init ( _ pathComponent: OpenAPIRuntime . RouterPathComponent ) {
64
- switch pathComponent {
65
- case . constant( let value) : self = . constant( value)
66
- case . parameter( let value) : self = . parameter( value)
63
+ extension [ Vapor . PathComponent ] {
64
+ init ( _ path: String ) {
65
+ self = path. split (
66
+ separator: " / " ,
67
+ omittingEmptySubsequences: false
68
+ ) . map { parameter in
69
+ if parameter. first == " { " , parameter. last == " } " {
70
+ return . parameter( String ( parameter. dropFirst ( ) . dropLast ( ) ) )
71
+ } else {
72
+ return . constant( String ( parameter) )
73
+ }
67
74
}
68
75
}
69
76
}
70
77
71
- extension OpenAPIRuntime . Request {
72
- init ( _ vaporRequest: Vapor . Request ) async throws {
73
- let headerFields : [ OpenAPIRuntime . HeaderField ] = . init( vaporRequest. headers)
74
-
75
- let bodyData = Data ( buffer: try await vaporRequest. body. collect ( upTo: . max) , byteTransferStrategy: . noCopy)
76
-
77
- let method = try OpenAPIRuntime . HTTPMethod ( vaporRequest. method)
78
-
78
+ extension HTTPTypes . HTTPRequest {
79
+ init ( _ vaporRequest: Vapor . Request ) throws {
80
+ let headerFields : HTTPTypes . HTTPFields = . init( vaporRequest. headers)
81
+ let method = try HTTPTypes . HTTPRequest. Method ( vaporRequest. method)
82
+ let queries = vaporRequest. url. query. map { " ? \( $0) " } ?? " "
79
83
self . init (
80
- path: vaporRequest. url. path,
81
- query: vaporRequest. url. query,
82
84
method: method,
83
- headerFields: headerFields,
84
- body: bodyData
85
+ scheme: vaporRequest. url. scheme,
86
+ authority: vaporRequest. url. host,
87
+ path: vaporRequest. url. path + queries,
88
+ headerFields: headerFields
85
89
)
86
90
}
87
91
}
88
92
89
- extension OpenAPIRuntime . ServerRequestMetadata {
90
- init (
91
- from vaporRequest: Vapor . Request ,
92
- forPath path: [ RouterPathComponent ] ,
93
- extractingQueryItemNamed queryItemNames: Set < String >
94
- ) throws {
93
+ extension OpenAPIRuntime . HTTPBody {
94
+ convenience init ( _ vaporRequest: Vapor . Request ) {
95
+ let contentLength = vaporRequest. headers. first ( name: " content-length " ) . map ( Int . init)
95
96
self . init (
96
- pathParameters: try . init( from: vaporRequest, forPath: path) ,
97
- queryParameters: . init( from: vaporRequest, queryItemNames: queryItemNames)
97
+ vaporRequest. body. map ( \. readableBytesView) ,
98
+ length: contentLength? . map { . known( $0) } ?? . unknown,
99
+ iterationBehavior: . single
98
100
)
99
101
}
100
102
}
101
103
102
- extension Dictionary where Key == String , Value == String {
103
- init ( from vaporRequest: Vapor . Request , forPath path: [ RouterPathComponent ] ) throws {
104
- let keysAndValues = try path. compactMap { item -> ( String , String ) ? in
105
- guard case let . parameter( name) = item else {
104
+ extension OpenAPIRuntime . ServerRequestMetadata {
105
+ init ( from vaporRequest: Vapor . Request , forPath path: String ) throws {
106
+ self . init ( pathParameters: try . init( from: vaporRequest, forPath: path) )
107
+ }
108
+ }
109
+
110
+ extension Dictionary < String , Substring > {
111
+ init ( from vaporRequest: Vapor . Request , forPath path: String ) throws {
112
+ let keysAndValues = try [ PathComponent] ( path) . compactMap { component throws -> String ? in
113
+ guard case let . parameter( parameter) = component else {
106
114
return nil
107
115
}
108
- guard let value = vaporRequest. parameters. get ( name) else {
109
- throw VaporTransportError . missingRequiredPathParameter ( name)
116
+ return parameter
117
+ } . map { parameter -> ( String , Substring ) in
118
+ guard let value = vaporRequest. parameters. get ( parameter) else {
119
+ throw VaporTransportError . missingRequiredPathParameter ( parameter)
110
120
}
111
- return ( name , value)
121
+ return ( parameter , Substring ( value) )
112
122
}
113
123
let pathParameterDictionary = try Dictionary ( keysAndValues, uniquingKeysWith: { _, _ in
114
124
throw VaporTransportError . duplicatePathParameter ( keysAndValues. map ( \. 0 ) )
@@ -117,41 +127,61 @@ extension Dictionary where Key == String, Value == String {
117
127
}
118
128
}
119
129
120
- extension Array where Element == URLQueryItem {
121
- init ( from vaporRequest: Vapor . Request , queryItemNames: Set < String > ) {
122
- let queryParameters = queryItemNames. sorted ( ) . compactMap { name -> URLQueryItem ? in
123
- guard let value = try ? vaporRequest. query. get ( String . self, at: name) else {
124
- return nil
125
- }
126
- return . init( name: name, value: value)
127
- }
128
- self = queryParameters
129
- }
130
- }
131
-
132
130
extension Vapor . Response {
133
- convenience init ( _ response: OpenAPIRuntime . Response ) {
131
+ convenience init ( response: HTTPTypes . HTTPResponse , body : OpenAPIRuntime . HTTPBody ? ) {
134
132
self . init (
135
- status: . init( statusCode: response. statusCode ) ,
133
+ status: . init( statusCode: response. status . code ) ,
136
134
headers: . init( response. headerFields) ,
137
- body: . init( data : response . body)
135
+ body: . init( body)
138
136
)
139
137
}
140
138
}
141
139
142
- extension Array where Element == OpenAPIRuntime . HeaderField {
140
+ extension Vapor . Response . Body {
141
+ init ( _ body: OpenAPIRuntime . HTTPBody ? ) {
142
+ guard let body else {
143
+ self = . empty
144
+ return
145
+ }
146
+ let stream : @Sendable ( any Vapor . BodyStreamWriter ) -> ( ) = { writer in
147
+ _ = writer. eventLoop. makeFutureWithTask {
148
+ do {
149
+ for try await chunk in body {
150
+ try await writer. write ( . buffer( ByteBuffer ( bytes: chunk) ) ) . get ( )
151
+ }
152
+ try await writer. write ( . end) . get ( )
153
+ } catch {
154
+ try await writer. write ( . error( error) ) . get ( )
155
+ }
156
+ }
157
+ }
158
+ switch body. length {
159
+ case let . known( count) :
160
+ self = . init( stream: stream, count: count)
161
+ case . unknown:
162
+ self = . init( stream: stream)
163
+ }
164
+ }
165
+ }
166
+
167
+ extension HTTPTypes . HTTPFields {
143
168
init ( _ headers: NIOHTTP1 . HTTPHeaders ) {
144
- self = headers. map { . init( name: $0. name, value: $0. value) }
169
+ self . init ( headers. compactMap { name, value in
170
+ guard let name = HTTPField . Name ( name) else {
171
+ return nil
172
+ }
173
+ return HTTPField ( name: name, value: value)
174
+ } )
145
175
}
146
176
}
147
177
148
178
extension NIOHTTP1 . HTTPHeaders {
149
- init ( _ headers: [ OpenAPIRuntime . HeaderField ] ) {
150
- self . init ( headers. map { ( $0. name, $0. value) } )
179
+ init ( _ headers: HTTPTypes . HTTPFields ) {
180
+ self . init ( headers. map { ( $0. name. rawName , $0. value) } )
151
181
}
152
182
}
153
183
154
- extension OpenAPIRuntime . HTTPMethod {
184
+ extension HTTPTypes . HTTPRequest . Method {
155
185
init ( _ method: NIOHTTP1 . HTTPMethod ) throws {
156
186
switch method {
157
187
case . GET: self = . get
@@ -168,7 +198,7 @@ extension OpenAPIRuntime.HTTPMethod {
168
198
}
169
199
170
200
extension NIOHTTP1 . HTTPMethod {
171
- init ( _ method: OpenAPIRuntime . HTTPMethod ) {
201
+ init ( _ method: HTTPTypes . HTTPRequest . Method ) {
172
202
switch method {
173
203
case . get: self = . GET
174
204
case . put: self = . PUT
@@ -178,7 +208,7 @@ extension NIOHTTP1.HTTPMethod {
178
208
case . head: self = . HEAD
179
209
case . patch: self = . PATCH
180
210
case . trace: self = . TRACE
181
- default : self = . RAW( value: method. name )
211
+ default : self = . RAW( value: method. rawValue )
182
212
}
183
213
}
184
214
}
0 commit comments