Skip to content

Commit

Permalink
client updates (vapor#2003)
Browse files Browse the repository at this point in the history
  • Loading branch information
tanner0101 authored Jun 13, 2019
1 parent 95d6c7e commit 844cba1
Show file tree
Hide file tree
Showing 8 changed files with 125 additions and 239 deletions.
127 changes: 18 additions & 109 deletions Sources/Vapor/Client/Client.swift
Original file line number Diff line number Diff line change
@@ -1,127 +1,36 @@
public protocol Client {
var eventLoop: EventLoop { get }
func send(_ request: ClientRequest) -> EventLoopFuture<ClientResponse>
func webSocket(_ request: ClientRequest, onUpgrade: @escaping (WebSocket) -> ()) -> EventLoopFuture<Void>
}

extension Client {
/// Sends an HTTP `GET` `Request` to a server with an optional configuration closure that will run before sending.
///
/// let res = try client.get("http://api.vapor.codes/users")
/// print(res) // Future<Response>
///
/// HTTP `GET` requests are typically used for fetching information and do not have bodies.
/// However, the `beforeSend` closure is a great place for encoding query string parameters.
///
/// let res = try client.get("http://api.vapor.codes/users") { get in
/// try get.query.encode(["name": "vapor"])
/// }
/// print(res) // Future<Response>
///
/// - parameters:
/// - url: Something `URLRepresentable` that will be converted to a `URL`.
/// This `URL` should contain a scheme, hostname, and port.
/// - headers: `HTTPHeaders` to add to the request. Empty by default.
/// - returns: A `Future` containing the requested `Response` or an `Error`.
public func get(_ url: URI, headers: HTTPHeaders = [:]) -> EventLoopFuture<ClientResponse> {
return self.send(.GET, headers: headers, to: url)
public func get(_ url: URI, headers: HTTPHeaders = [:], beforeSend: (inout ClientRequest) throws -> () = { _ in }) -> EventLoopFuture<ClientResponse> {
return self.send(.GET, headers: headers, to: url, beforeSend: beforeSend)
}

/// Sends an HTTP `POST` `Request` to a server with an optional configuration closure that will run before sending.
///
/// let user: User ...
/// let res = try client.post("http://api.vapor.codes/users") { post in
/// try post.content.encode(user)
/// }
/// print(res) // Future<Response>
///
/// - parameters:
/// - url: Something `URLRepresentable` that will be converted to a `URL`.
/// This `URL` should contain a scheme, hostname, and port.
/// - headers: `HTTPHeaders` to add to the request. Empty by default.
/// - returns: A `Future` containing the requested `Response` or an `Error`.
public func post(_ url: URI, headers: HTTPHeaders = [:]) -> EventLoopFuture<ClientResponse> {
return self.send(.POST, headers: headers, to: url)
public func post(_ url: URI, headers: HTTPHeaders = [:], beforeSend: (inout ClientRequest) throws -> () = { _ in }) -> EventLoopFuture<ClientResponse> {
return self.send(.POST, headers: headers, to: url, beforeSend: beforeSend)
}

/// Sends an HTTP `PATCH` `Request` to a server with an optional configuration closure that will run before sending.
///
/// let user: User ...
/// let res = try client.patch("http://api.vapor.codes/users/42") { patch in
/// try patch.content.encode(user)
/// }
/// print(res) // Future<Response>
///
/// - parameters:
/// - url: Something `URLRepresentable` that will be converted to a `URL`.
/// This `URL` should contain a scheme, hostname, and port.
/// - headers: `HTTPHeaders` to add to the request. Empty by default.
/// - returns: A `Future` containing the requested `Response` or an `Error`.
public func patch(_ url: URI, headers: HTTPHeaders = [:]) -> EventLoopFuture<ClientResponse> {
return self.send(.PATCH, headers: headers, to: url)
public func patch(_ url: URI, headers: HTTPHeaders = [:], beforeSend: (inout ClientRequest) throws -> () = { _ in }) -> EventLoopFuture<ClientResponse> {
return self.send(.PATCH, headers: headers, to: url, beforeSend: beforeSend)
}

/// Sends an HTTP `PUT` `Request` to a server with an optional configuration closure that will run before sending.
///
/// let user: User ...
/// let res = try client.put("http://api.vapor.codes/users/42") { put in
/// try put.content.encode(user)
/// }
/// print(res) // Future<Response>
///
/// - parameters:
/// - url: Something `URLRepresentable` that will be converted to a `URL`.
/// This `URL` should contain a scheme, hostname, and port.
/// - headers: `HTTPHeaders` to add to the request. Empty by default.
/// - returns: A `Future` containing the requested `Response` or an `Error`.
public func put(_ url: URI, headers: HTTPHeaders = [:]) -> EventLoopFuture<ClientResponse> {
return self.send(.PUT, headers: headers, to: url)
public func put(_ url: URI, headers: HTTPHeaders = [:], beforeSend: (inout ClientRequest) throws -> () = { _ in }) -> EventLoopFuture<ClientResponse> {
return self.send(.PUT, headers: headers, to: url, beforeSend: beforeSend)
}

/// Sends an HTTP `DELETE` `Request` to a server with an optional configuration closure that will run before sending.
///
/// let res = try client.delete("http://api.vapor.codes/users/42")
/// print(res) // Future<Response>
///
/// HTTP `DELETE` requests are typically used for deleting information and do not have bodies.
/// However, the `beforeSend` closure is a great place for encoding query string parameters.
///
/// let res = try client.delete("http://api.vapor.codes/users") { get in
/// try get.query.encode(["name": "vapor"])
/// }
/// print(res) // Future<Response>
///
/// - parameters:
/// - url: Something `URLRepresentable` that will be converted to a `URL`.
/// This `URL` should contain a scheme, hostname, and port.
/// - headers: `HTTPHeaders` to add to the request. Empty by default.
/// - beforeSend: An optional closure that can mutate the `Request` before it is sent.
/// - returns: A `Future` containing the requested `Response` or an `Error`.
public func delete(_ url: URI, headers: HTTPHeaders = [:]) -> EventLoopFuture<ClientResponse> {
return self.send(.DELETE, headers: headers, to: url)
public func delete(_ url: URI, headers: HTTPHeaders = [:], beforeSend: (inout ClientRequest) throws -> () = { _ in }) -> EventLoopFuture<ClientResponse> {
return self.send(.DELETE, headers: headers, to: url, beforeSend: beforeSend)
}

/// Sends an HTTP `Request` to a server with an optional configuration closure that will run before sending.
///
/// let user: User ...
/// let res = try client.send(.POST, to: "http://api.vapor.codes/users") { post in
/// try post.content.encode(user)
/// }
/// print(res) // Future<Response>
///
/// - parameters:
/// - method: `HTTPMethod` to use for the request.
/// - headers: `HTTPHeaders` to add to the request. Empty by default.
/// - url: Something `URLRepresentable` that will be converted to a `URL`.
/// This `URL` should contain a scheme, hostname, and port.
/// - beforeSend: An optional closure that can mutate the `Request` before it is sent.
/// - returns: A `Future` containing the requested `Response` or an `Error`.
public func send(_ method: HTTPMethod, headers: HTTPHeaders = [:], to url: URI) -> EventLoopFuture<ClientResponse> {
let request = ClientRequest(method: method, url: url, headers: headers, body: nil)
public func send(_ method: HTTPMethod, headers: HTTPHeaders = [:], to url: URI, beforeSend: (inout ClientRequest) throws -> () = { _ in }) -> EventLoopFuture<ClientResponse> {
var request = ClientRequest(method: method, url: url, headers: headers, body: nil)
do {
try beforeSend(&request)
} catch {
return self.eventLoop.makeFailedFuture(error)
}
return self.send(request)
}


public func webSocket(_ url: URI, headers: HTTPHeaders = [:], onUpgrade: @escaping (WebSocket) -> ()) -> EventLoopFuture<Void> {
return self.webSocket(ClientRequest(method: .GET, url: url, headers: headers, body: nil), onUpgrade: onUpgrade)
}
}
47 changes: 0 additions & 47 deletions Sources/Vapor/Client/ClientProvider.swift

This file was deleted.

80 changes: 0 additions & 80 deletions Sources/Vapor/Client/DefaultClient.swift

This file was deleted.

26 changes: 26 additions & 0 deletions Sources/Vapor/Client/HTTPClient+Client.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
extension HTTPClient: Client {
public var eventLoop: EventLoop {
return self.eventLoopGroup.next()
}

public func send(_ client: ClientRequest) -> EventLoopFuture<ClientResponse> {
do {
let request = try HTTPClient.Request(
url: URL(string: client.url.string)!,
version: .init(major: 1, minor: 1),
method: client.method,
headers: client.headers, body: client.body.flatMap { .byteBuffer($0) }
)
return self.execute(request: request).map { response in
let client = ClientResponse(
status: response.status,
headers: response.headers,
body: response.body
)
return client
}
} catch {
return self.eventLoop.makeFailedFuture(error)
}
}
}
44 changes: 44 additions & 0 deletions Sources/Vapor/Client/WebSocketClient+Helpers.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
extension WebSocketClient {
public func webSocket(_ url: URI, headers: HTTPHeaders = [:], onUpgrade: @escaping (WebSocket) -> ()) -> EventLoopFuture<Void> {
return self.webSocket(ClientRequest(method: .GET, url: url, headers: headers, body: nil), onUpgrade: onUpgrade)
}
public func webSocket(_ request: ClientRequest, onUpgrade: @escaping (WebSocket) -> ()) -> EventLoopFuture<Void> {
let port: Int
if let p = request.url.port {
port = p
} else if let scheme = request.url.scheme {
port = scheme == "wss" ? 443 : 80
} else {
port = 80
}
return self.connect(host: request.url.host ?? "", port: port, uri: request.url.path, headers: request.headers) { socket in
onUpgrade(socket)
}
}
}

extension WebSocketClient.Socket: WebSocket {
public func onText(_ callback: @escaping (WebSocket, String) -> ()) {
self.onText { (ws: WebSocketClient.Socket, data: String) in
callback(ws, data)
}
}

public func onBinary(_ callback: @escaping (WebSocket, ByteBuffer) -> ()) {
self.onBinary { (ws: WebSocketClient.Socket, data: ByteBuffer) in
callback(ws, data)
}
}

public func onError(_ callback: @escaping (WebSocket, Error) -> ()) {
self.onError { (ws: WebSocketClient.Socket, error: Error) in
callback(ws, error)
}
}

public func send(binary: ByteBuffer, promise: EventLoopPromise<Void>?) {
var binary = binary
self.send(binary: binary.readBytes(length: binary.readableBytes)!, promise: promise)
}
}

18 changes: 17 additions & 1 deletion Sources/Vapor/Services/Services+Default.swift
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,23 @@ extension Services {
var s = Services()

// client
s.provider(ClientProvider())
s.register(HTTPClient.Configuration.self) { c in
return .init()
}
s.register(Client.self) { c in
return try c.make(HTTPClient.self)
}
s.register(HTTPClient.self) { c in
return try .init(eventLoopGroupProvider: .shared(c.eventLoop), configuration: c.make())
}

// ws client
s.register(WebSocketClient.Configuration.self) { c in
return .init()
}
s.register(WebSocketClient.self) { c in
return try .init(eventLoopGroupProvider: .shared(c.eventLoop), configuration: c.make())
}

// auth
s.register(PasswordVerifier.self) { c in
Expand Down
Loading

0 comments on commit 844cba1

Please sign in to comment.