✎ Edit on GitHub

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.

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:

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

POST as json

let jsonBytes = myJSON.makeBytes()
try drop.client.post("http://some-endpoint/json", headers: ["Auth": "Token my-auth-token"], body: .data(jsonBytes))

POST as x-www-form-urlencoded

try drop.client.post("http://some-endpoint", headers: [
  "Content-Type": "application/x-www-form-urlencoded"
], body: Body.data( Node([
  "email": "mymail@vapor.codes"
]).formURLEncoded()))               

Full Request

To access additional functionality or custom methods, use the underlying request function directly.

public static func get(_ method: Method,
                       _ uri: String,
                       headers: [HeaderKey: String] = [:],
                       query: [String: CustomStringConvertible] = [:],
                       body: Body = []) throws -> Response

For example:

try drop.client.request(.other(method: "CUSTOM"), "http://some-domain", headers: ["My": "Header"], query: ["key": "value"], body: [])

Config

The Config/clients.json file can be used to modify the client's settings.

TLS

Host and certificate verification can be disabled.

Note: Use extreme caution when modifying these settings.

{
    "tls": {
        "verifyHost": false,
        "verifyCertificates": false
    }
}

Mozilla

The Mozilla certificates are included by default to make fetching content from secure sites easy.

{
    "tls": {
        "certificates": "mozilla"
    }
}

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:

let response = try Client<TCPClientStream>.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.

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:

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:

let drop = Droplet()

drop.client = MyCustomClient.self

Going forward, all of your calls to drop.client will use MyCustomClient.self:

drop.client.get(... // uses `MyCustomClient`