From cb2a57ef5eb62cfb903e35110c5d0d8b2dd88ed0 Mon Sep 17 00:00:00 2001 From: Logan Wright Date: Wed, 3 Aug 2016 22:22:12 -0400 Subject: [PATCH] client docs --- couscous.yml | 3 ++ http/client.md | 130 +++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 133 insertions(+) create mode 100644 http/client.md diff --git a/couscous.yml b/couscous.yml index 6a02a3f9..77e915e9 100644 --- a/couscous.yml +++ b/couscous.yml @@ -86,3 +86,6 @@ menu: guide-responder: text: Responder relativeUrl: http/responder.html + guide-client: + text: Client + relativeUrl: http/client.html diff --git a/http/client.md b/http/client.md new file mode 100644 index 00000000..6c1a1cab --- /dev/null +++ b/http/client.md @@ -0,0 +1,130 @@ +--- +currentMenu: http-client +--- + +> Module: `import HTTP` + +# Client + +The client provided by `HTTP` is used to make outgoing requests to remote servers. Let's look at a simple outgoing request. + +## QuickStart + +Let's jump right in to make a simple HTTP Request. Here's a basic `GET` request using your Vapor `Droplet`. + +```swift +let query = ... +let spotifyResponse = try drop.client.get("https://api.spotify.com/v1/search?type=artist&q=\(query)") +print(spotifyR) +``` + +### Clean Up + +The url above can be a little tricky to read, so let's use the query parameter to clean it up a little bit: + +```swift +try drop.client.get("https://api.spotify.com/v1/search", query: ["type": "artist", "q": query]) +``` + +### Continued + +In addition to `GET` requests, Vapor's client provides support for most common HTTP functions. `GET`, `POST`, `PUT`, `PATCH`, `DELETE` + +```swift +let bytes = myJSON.makeBytes() +try drop.client.post("http://some-endpoint/json", headers: ["Auth": "Token my-auth-token"], body: .data(jsonBytes)) +``` + +### Full Request + +To access additional functionality or custom methods, use the underlying `request` function directly. + +```swift +public static func get(_ method: Method, + _ uri: String, + headers: [HeaderKey: String] = [:], + query: [String: CustomStringConvertible] = [:], + body: Body = []) throws -> Response +``` + +For example: + +```swift +try drop.client.request(.other(method: "CUSTOM"), "http://some-domain", headers: ["My": "Header"], query: ["key": "value"], body: []) +``` + +## Advanced + +In addition to our Droplet, we can also use and interact with the `Client` manually. Here's how our default implementation in Vapor looks: + +```swift +let response = try Client.get("http://some-endpoint/mine") +``` + +The first thing we likely noticed is `TCPClientStream` being used as a Generic value. This will be the underlying connection that the `HTTP.Client` can use when performing the request. By conforming to the underlying `ClientStream`, an `HTTP.Client` can accept custom stream implementations seamlessly. + +## Save Connection + +Up to this point, we've been interacting with the Client via `class` or `static` level functions. This allows us to end the connection upon a completed request and is the recommended interaction for most use cases. For some advanced situations, we may want to reuse a connection. For these, we can initialize our client and perform multiple requests like this. + +```swift +let pokemonClient = try drop?.client.make(scheme: "http", host: "pokeapi.co") +for i in 0...1 { + let response = try pokemonClient?.get(path: "/api/v2/pokemon/", query: ["limit": 20, "offset": i]) + print("response: \(response)") +} +``` + +## ClientProtocol + +Up to this point, we've focused on the built in `HTTP.Client`, but users can also include their own customized clients by conforming to `HTTP.ClientProtocol`. Let's look at the implementation: + +```swift +public protocol Responder { + func respond(to request: Request) throws -> Response +} + +public protocol Program { + var host: String { get } + var port: Int { get } + var securityLayer: SecurityLayer { get } + // default implemented + init(host: String, port: Int, securityLayer: SecurityLayer) throws +} + +public protocol ClientProtocol: Program, Responder { + var scheme: String { get } + var stream: Stream { get } + init(scheme: String, host: String, port: Int, securityLayer: SecurityLayer) throws +} +``` + +By conforming to these underlying functions, we immediately gain access to the public `ClientProtocol` apis we viewed above. + +## Customize Droplet + +If we've introduced a custom conformance to `HTTP.ClientProtocol`, we can pass this into our droplet without changing the underlying behavior in our application. + +For example: + +```swift +let drop = Droplet(client: MyCustomClient.self) +``` + +Going forward, all of your calls to `drop.client` will use `MyCustomClient.self`: + +```swift +drop.client.get(... // uses `MyCustomClient` +``` + +### Provider + +We can also use Providers to inherit behavior in our application. For example, to add Linux compatible TLS to our application's `Client`, we might use this: + +```swift +import VaporTLS + +let drop = Droplet(initializedProviders: [VaporTLS.Provider(.client)]) +``` + +In the same way as above, this will now apply to all `drop.client` calls within our application.