Skip to content

Using HTTP Message

There are two types of HTTP messages, HTTPRequest and HTTPResponse. For the most part they are very similar, but there are a couple of differences.

Request

HTTP requests are sent by clients to a server and they should always receive exactly one HTTP response. HTTP requests contain two unique fields over a standard HTTP message:

The method and URL define what content on the server is being requested.

/// GET /hello
let httpReq = HTTPRequest(method: .GET, url: "/hello")

You can define these when initializing an HTTP request, or set them later if the request is mutable.

var httpReq: HTTPRequest = ...
httpReq.method = .POST
httpReq.url = URL(...)

You can use Foundation's URLComponents to create URLs from their base components. HTTP request also has a property urlString that you can use to set a custom URL String manually, without going through URL.

Here is what a serialized HTTP request looks like. This one is querying /hello.

GET /hello HTTP/1.1
Content-Length: 0

Response

HTTP responses are generated by servers in response to an HTTP request. HTTP response only has one unique field over general HTTP messages:

The HTTP status is used to inform the client of any errors. The status consists of a status code and a reason. The code is always a three digit number and the reason is a short string explaining the code. You can see all of the status codes on httpstatuses.com. You can find the the Swift struct and built-in status properties in the Swift-NIO repo.

let httpRes = HTTPResponse(status: .ok, body: "hello")

All of the commonly used HTTP statuses will have pre-defined values you can use, like .ok for 200 OK. You can also define your own custom status codes.

You can define the status when initializing an HTTP response, or set it later if the response is mutable.

var httpRes: HTTPResponse = ...
httpRes.status = .notFound

Here is an example of a serialized HTTP response.

HTTP/1.1 200 OK
Content-Length: 5
Content-Type: text/plain

hello

Headers

Every HTTP message has a collection of headers. Headers contain metadata about the message and help to explain what is in the message's body.

Content-Length: 5
Content-Type: text/plain

There must be at least a "Content-Length" or "Transfer-Encoding" header to define how long the message's body is. There is almost always a "Content-Type" header that explains what type of data the body contains. There are many other common headers such as "Date" which specifies when the message was created, and more.

You can access an HTTP message's headers using the headers property.

var message: HTTPMessage ...
message.headers.firstValue(for: .contentLength) // 5

If you are interacting with common HTTP headers, you can use the convenience HTTP names instead of a raw String.

Body

HTTP messages can have an HTTPBody containing arbitrary data. This data can be either static or streaming and can be in whatever format you want. Use the contentType header to describe the type of data.

var message: HTTPMessage = ...
message.body = HTTPBody(string: "Hello, world!")
message.contentType = .plainText

Tip

Setting the body property will automatically update the "Content-Length" or "Transfer-Encoding" headers if required.

var message: HTTPMessage = ...
message.body = HTTPBody(string: """
{"message": "Hello, world!"}
""")
message.contentType = .json

Codable

Two protocols are defined for making it easy to use Codable with HTTP:

These two coders allow you to encode and decode your custom Codable types into an HTTP body, setting the appropriate content type headers.

By default, HTTP provides conformance for JSONEncoder and JSONDecoder, but Vapor includes coders for many more types.

Here is an example of encoding a Codable struct to an HTTP response.

struct Greeting: Codable {
    var message: String
}
// Create an instance of Greeting
let greeting = Greeting(message: "Hello, world!")
// Create a 200 OK response
var httpRes = HTTPResponse(status: .ok)
// Encode the greeting to the response
try JSONEncoder().encode(greeting, to: &httpRes, on: ...)

API Docs

Check out the API docs for more in-depth information about all of the methods.