vapor-docs/3.0/docs/http/message.md

137 lines
5.4 KiB
Markdown

# Using HTTP Message
There are two types of HTTP messages, [`HTTPRequest`](https://api.vapor.codes/http/latest/HTTP/Structs/HTTPRequest.html) and [`HTTPResponse`](https://api.vapor.codes/http/latest/HTTP/Structs/HTTPResponse.html). 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:
- [`method`](https://api.vapor.codes/http/latest/HTTP/Structs/HTTPRequest.html#/s:4HTTP11HTTPRequestV6methodXev)
- [`url`](https://api.vapor.codes/http/latest/HTTP/Structs/HTTPRequest.html#/s:4HTTP11HTTPRequestV3urlXev)
The method and URL define what content on the server is being requested.
```swift
/// 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.
```swift
var httpReq: HTTPRequest = ...
httpReq.method = .POST
httpReq.url = URL(...)
```
You can use Foundation's `URLComponents` to create `URL`s from their base components. HTTP request also has a property [`urlString`](https://api.vapor.codes/http/latest/HTTP/Structs/HTTPRequest.html#/s:4HTTP11HTTPRequestV9urlStringSSv) 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`.
```http
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:
- [`status`](https://api.vapor.codes/http/latest/HTTP/Structs/HTTPResponse.html#/s:4HTTP12HTTPResponseV6statusXev)
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](https://httpstatuses.com). You can find the the Swift struct and built-in status properties in the [Swift-NIO](https://apple.github.io/swift-nio/docs/current/NIOHTTP1/Enums/HTTPResponseStatus.html) repo.
```swift
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.
```swift
var httpRes: HTTPResponse = ...
httpRes.status = .notFound
```
Here is an example of a serialized HTTP response.
```http
HTTP/1.1 200 OK
Content-Length: 5
Content-Type: text/plain
```
## 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.
```http
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.
```swift
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`](https://api.vapor.codes/http/latest/HTTP/Structs/HTTPBody.html) containing arbitrary data. This data can be either static or streaming and can be in whatever format you want. Use the [`contentType`](https://api.vapor.codes/http/latest/HTTP/Protocols/HTTPMessage.html#/s:4HTTP11HTTPMessagePAAE11contentTypeXev) header to describe the type of data.
```swift
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.
```swift
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:
- [`HTTPMessageEncoder`](https://api.vapor.codes/http/latest/HTTP/Protocols/HTTPMessageEncoder.html)
- [`HTTPMessageDecoder`](https://api.vapor.codes/http/latest/HTTP/Protocols/HTTPMessageDecoder.html)
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.
```swift
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](https://api.vapor.codes/http/latest/HTTP/index.html) for more in-depth information about all of the methods.