Request¶
The most common part of the HTTP
library we'll be interacting with is the Request
type. Here's a look at some of the most commonly used attributes in this type.
public var method: Method public var uri: URI public var parameters: Node public var headers: [HeaderKey: String] public var body: Body public var data: Content
Method¶
The HTTP Method
associated with the Request
, ie: GET
, POST
, PUT
, PATCH
, DELETE
.
URI¶
The associated URI
of the request. We will use this to access attributes about the uri
the request was sent to.
For example, given the following uri: http://vapor.codes/example?query=hi#fragments-too
let scheme = request.uri.scheme // http let host = request.uri.host // vapor.codes let path = request.uri.path // /example let query = request.uri.query // query=hi let fragment = request.uri.fragment // fragments-too
Route Parameters¶
The url parameters associated with the request. For example, if we have a path registered as hello/:name/age/:age
, we would be able to access those in our request, like so:
let name = request.parameters["name"] // String? let age = request.parameters["age"]?.int // Int?
Or, to automatically throw on nil
or invalid variable, you can also extract
let name = try request.parameters.extract("name") as String let age = try request.parameters.extract("age") as Int
These extract functions can cast to any NodeInitializable
type, including your own custom types. Make sure to check out Node for more info.
Note: Vapor also provides type safe routing in the routing section of our docs.
Headers¶
These are the headers associated with the request. If you are preparing an outgoing request, this can be used to add your own keys.
let contentType = request.headers["Content-Type"]
Or for outgoing requests:
let request = Request ... request.headers["Content-Type"] = "application/json" request.headers["Authorization"] = ... my auth token
Extending Headers¶
We generally seek to improve code bases by removing stringly typed code where possible. We can add variables to the headers using generic extensions.
extension HTTP.KeyAccessible where Key == HeaderKey, Value == String { var customKey: String? { get { return self["Custom-Key"] } set { self["Custom-Key"] = newValue } } }
With this pattern implemented, our string "Custom-Key"
is contained in one section of our code. We can now access like this:
let customKey = request.headers.customKey // or let request = ... request.headers.customKey = "my custom value"
Body¶
This is the body associated with the request and represents the general data payload. You can view more about body in the associated docs
For incoming requests, we'll often pull out the associated bytes like so:
let rawBytes = request.body.bytes
Content¶
Generally when we're sending or receiving requests, we're using them as a way to transport content. For this, Vapor provides a convenient data
variable associated with the request that prioritizes content in a consistent way.
For example, say I receive a request to http://vapor.codes?hello=world
.
let world = request.data["hello"]?.string
This same code will work if I receive a JSON request, for example:
{ "hello": "world" }
Will still be accessible through data.
let world = request.data["hello"]?.string
Note: Force unwrap should never be used.
This also applies to multi-part requests and can even be extended to new types such as XML or YAML through middleware.
If you'd prefer to access given types more explicitly, that's totally fine. The data
variable is purely opt-in convenience for those who want it.
Form Data¶
It is common in many applications to receive forms submitted from a Web browser. Vapor provides support for several common encodings:
// Node? from application/x-www-form-urlencoded let formData = request.formURLEncoded // [String:Field]? from multipart/form-data let multipartFormData = request.formData // [Part]? from multipart/mixed let multipartMixedData = request.multipart
These accessors will return nil
if the request's Content-Type
does not match what they expect.
JSON¶
To access JSON directly on a given request, use the following:
let json = request.json["hello"]
Query Parameters¶
The same applies to query convenience:
let query = request.query?["hello"] // String? let name = request.query?["name"]?.string // String? let age = request.query?["age"]?.int // Int? let rating = request.query?["rating"]?.double // Double?
Key Paths¶
Key paths work on most Vapor types that can have nested key value objects. Here's a couple examples of how to access given the following json:
{ "metadata": "some metadata", "artists" : { "href": "http://someurl.com", "items": [ { "name": "Van Gogh", }, { "name": "Mozart" } ] } }
We could access the data in the following ways:
Metadata¶
Access top level values
let type = request.data["metadata"].string // "some metadata"
Items¶
Access nested values
let items = request.data["artists", "items"] // [["name": "Van Gogh"], ["name": "Mozart"]]
Mixing Arrays and Objects¶
Get first artists
let first = request.data["artists", "items", 0] // ["name": "Van Gogh"]
Array Item¶
Get key from array item
let firstName = request.data["artists", "items", 0, "name"] // "Van Gogh"
Array Comprehension¶
We can also smartly map an array of keys, for example, to just get the names of all of the artists, we could use the following
let names = request.data["artists", "items", "name"] // ["Van Gogh", "Mozart"]