Requests
Introduction
The Request
object encapsulates incoming HTTP requests to your Alchemy app. It provides a variety of ways to interact with each request’s content, queries, files, and more. We will discuss a few of the most important methods below.
Inspecting the Request
A Request
object is passed to the handlers of each route you define on your app.
Request Path & Method
Each Request
instance contains an instance of Foundation’s URLComponents
as well as an HTTPMethod
, urlComponents
and method
, respectively. It also contains a few functions and properties for shorthand access to other common values.
Accessing The Request URL
You can access the complete url of the request using the url
field.
You may also access just the path of the request. In example, the request url is “https://example.com/users/2” path
will be /users/2
. Note that path will not include any query from the url.
Accessing Parameters
You’ll often have path parameters in your routes, specified on your router by a path component prefixed with a :
. To quickly access any path parameters on a request, you may use the parameter()
function.
You may specific the return type to be any implementation of LosslessStringConvertible
(a type that’s initializable from a String
). This overload of the function has a throwing interface, and will throw if the parameter doesn’t exist or isn’t convertible.
If you’d like to iterate over each parameter, you may access the parameters
property. Each Parameter
has a key
and value
, representing the path placeholder and the actual component string, respectively.
Retreiving The Request Method
You may access the request’s method via the method
property.
Request Headers
You can grab a single header value from a request using the header()
function.
The header()
function returns the first matching header value, if one exists. If you’d like to access multiple values of the same header, you may use the headers
parameter, an instance of HTTPHeaders
.
Retrieving Values From The Query String
Values in the query string is easily accessible via the query()
function.
Request IP Address
You may access the remote address of the incoming response via the remoteAddress
field, an instance of swift-nio’s SocketAddress?
.
If you’d prefer to just access the ip address String
, use ip
.
Content
Incoming requests will often have content in the request body. You can access the raw body data via the request.body
property, but Alchemy includes a few higher level interfaces for interacting with the request content.
Decoding Codable Types
Typically, incoming requests will have their body encoded in one of a few common encoding standards, as indicated by the Content-Type
header. Out of the box, Alchemy lets you decode Swift Codable
types from requests encoded by multipart/form-data
, application/x-www-form-urlencoded
, and application/json
.
The decode()
function automatically detects the right decoder to use based on the Content-Type
header, but you may pass it a specific decoder if you’d like to specify additional options.
Writing A Custom Decoder
If you’d like to use the decoding APIs with a unsupported content type, you’ll need to write a custom implementation of ContentDecoder
and pass it to the decode()
function.
Accessing Specific Fields
While decoding can be a great way to quickly validate incoming requests against a complicated schema, it can be brittle and requires a custom type for decoding all types. To simplify cases where you only need a single field or two, you may use the Content
API, which seamlessly integrates a dictionary-like lookup style and Swift’s Codable
.
Retreiving Content At A Specific Path
You may access a request’s content with the content()
function or through subscripting directly on Request
. Subscripts can be either String
s for fields or Int
s for array index access.
You may also use dynamic member lookup.
Checking If A Value Exists
You may confirm that a value exists at the given path using the exists
property.
Checking For Null
A value that exists but is null
can be checked for using the isNull
property.
Retrieving Data
Once you’ve accessed the content at the proper path, there are a few variables and functions to help convert that data to a desired type.
Retreiving A Value
You may retrive a value from the content at a specific path using the string
, int
, bool
, double
, and array
properties. Each has a throwing version as well.
Each property has a throwing version as well that throws if there is an error converting or if the value doesn’t exist.
Decoding A Value
You may also combine the dynamic interface of Content
with the typesafe interface of Codable
by calling decode()
on content at the given path.
Dot Notation
When working with content that’s an array, you may subscript with the *
operator to “flatten” it, often called “dot” notation. This returns an array of Content
and subsequent subscripts will be applied to each element.
Dictionaries / Objects
Dot notation is also applicable to dictionaries/objects in your content, and will map each key/value pair to the value.
Files
Retrieving Uploaded Files
You may quickly retrieve any files uploaded as part of the request using the file()
method, or by using the file
/fileThrowing
properties on Content
. These return an instance of type File
which provides a variety of utilities for interacting with the file.
Accessing The File Content Type
If the file was uploaded with a Content-Type
header, you may access it with the contentType
property.
Storing Uploaded Files
To store an uploaded file, you’ll want to put it in one of your filesystems. You can use File’s store()
function to do so easily. It accepts an optional directory to put the file in, as well as an optional id of the filesystem to store in. By default, it will be stored in your default filesystem.