Skip to content

Commit 5f03276

Browse files
guoye-zhangApple Democthielen
authored
Add blog post "Introducing Swift HTTP Types" (#337)
* Add blog post "Introducing Swift HTTP Types" * Editorial pass * swift-nio-extras integration is not available yet * Additional editorial * Remove action --------- Co-authored-by: Apple Demo <[email protected]> Co-authored-by: Christopher Thielen <[email protected]>
1 parent 51e157f commit 5f03276

File tree

2 files changed

+179
-0
lines changed

2 files changed

+179
-0
lines changed

_data/authors.yml

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -375,3 +375,15 @@ simonjbeaumont:
375375
376376
github: simonjbeaumont
377377
about: "Si Beaumont is a member of a team developing foundational server-side Swift libraries as part of Apple’s Services Engineering division, and is a core developer on Swift OpenAPI Generator."
378+
379+
guoyezhang:
380+
name: Guoye Zhang
381+
382+
github: guoye-zhang
383+
about: "Guoye Zhang is a member of the team at Apple working on Foundation networking, HTTP, and other internet technologies."
384+
385+
erickinnear:
386+
name: Eric Kinnear
387+
388+
github: ekinnear
389+
about: "Eric Kinnear is a member of the team at Apple working on Foundation networking, HTTP, and other internet technologies."
Lines changed: 167 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,167 @@
1+
---
2+
layout: post
3+
published: true
4+
date: 2023-07-10 10:00:00
5+
title: Introducing Swift HTTP Types
6+
author: [guoyezhang, erickinnear, corybenfield]
7+
---
8+
9+
We're excited to announce a new open source package called [Swift HTTP Types](https://github.com/apple/swift-http-types).
10+
11+
Building upon insights from Swift on server, app developers, and the broader Swift community, Swift HTTP Types is designed to provide a shared set of currency types for client/server HTTP operations in Swift.
12+
13+
## HTTP in Swift
14+
15+
Networking in Swift is ubiquitous for many use cases today, spanning clients, servers, intermediaries, and many other participants across the internet and other networks. HTTP is among the most popular networking technologies, powering daily experiences across the world.
16+
17+
On Apple platforms, the system HTTP implementation is exposed via the `URLSession` API in the Foundation framework. For Swift on server projects, the recommended HTTP stack is implemented in [SwiftNIO](https://github.com/apple/swift-nio).
18+
19+
To provide the best possible experience for using HTTP in Swift, shared currency types, useful across many projects, are essential.
20+
21+
## Swift HTTP Types
22+
23+
[Swift HTTP Types](https://github.com/apple/swift-http-types) provides a common representation of the core building blocks of HTTP messages.
24+
25+
`HTTPRequest` and `HTTPResponse` represent HTTP messages for both client and server use cases. By adopting them across multiple projects, more code can be shared between clients and servers, eliminating the cost of converting between types when working with multiple frameworks.
26+
27+
These types are built Swift-first to represent every valid HTTP message. Their representations are focused on modern HTTP versions like HTTP/3 and HTTP/2, while also retaining compatibility with HTTP/1.1.
28+
29+
As the package matures, our goal is to replace SwiftNIO's `HTTPRequestHead` and `HTTPResponseHead` as well as the HTTP message details of Foundation's `URLRequest` and `URLResponse`.
30+
31+
The new currency types are designed to be suitable for use in any HTTP scenario and are not tied to any existing framework, eliminating the need for duplicate HTTP abstractions.
32+
33+
## Example Usage
34+
35+
The API is designed to offer ergonomic ways to perform the most common HTTP operations, while scaling cleanly to represent advanced use cases.
36+
37+
At their core, HTTP requests are comprised of a method, a scheme, an authority, and a path:
38+
39+
```swift
40+
let request = HTTPRequest(method: .get, scheme: "https", authority: "www.example.com", path: "/")
41+
```
42+
43+
We can also create the same request from a Foundation URL:
44+
45+
```swift
46+
var request = HTTPRequest(method: .get, url: URL(string: "https://www.example.com/")!)
47+
```
48+
49+
We can change the method, or other properties, after the fact:
50+
51+
```swift
52+
request.method = .post
53+
request.path = "/upload"
54+
```
55+
56+
Creating a response is similarly straightforward:
57+
58+
```swift
59+
let response = HTTPResponse(status: .ok)
60+
```
61+
62+
We can access and modify header fields using the `headerFields` property:
63+
64+
```swift
65+
request.headerFields[.userAgent] = "MyApp/1.0"
66+
```
67+
68+
Common header fields are built-in, and we can easily provide extensions for custom header fields and values, so we can use the same convenient syntax in our business logic:
69+
70+
```swift
71+
extension HTTPField.Name {
72+
static let myCustomHeader = Self("My-Custom-Header")!
73+
}
74+
75+
request.headerFields[.myCustomHeader] = "custom-value"
76+
```
77+
78+
We can directly set the value of the header field, including an array of values:
79+
80+
```swift
81+
request.headerFields[raw: .acceptLanguage] = ["en-US", "zh-Hans-CN"]
82+
```
83+
84+
Accessing header fields is much the same, and we can use system-defined fields or our own extensions:
85+
86+
```swift
87+
request.headerFields[.userAgent] // "MyApp/1.0"
88+
request.headerFields[.myCustomHeader] // "custom-value"
89+
90+
request.headerFields[.acceptLanguage] // "en-US, zh-Hans-CN"
91+
request.headerFields[raw: .acceptLanguage] // ["en-US", "zh-Hans-CN"]
92+
```
93+
94+
### Integrating with Foundation
95+
96+
Using `URLSession`, we can easily create a new `HTTPRequest` to send a POST request to "www.example.com". Setting a custom `User-Agent` header field value on this request is intuitive and integrates with the type system to offer auto-completions:
97+
98+
```swift
99+
var request = HTTPRequest(method: .post, url: URL(string: "https://www.example.com/upload")!)
100+
request.headerFields[.userAgent] = "MyApp/1.0"
101+
let (responseBody, response) = try await URLSession.shared.upload(for: request, from: requestBody)
102+
guard response.status == .created else {
103+
// Handle error
104+
}
105+
```
106+
107+
### Integrating with SwiftNIO
108+
109+
SwiftNIO integration will be available in the [swift-nio-extras](https://github.com/apple/swift-nio-extras) package when this package becomes stable. To configure a NIO channel handler for use with the new HTTP types, we can add `HTTP2FramePayloadToHTTPServerCodec` before our other channel handlers:
110+
111+
```swift
112+
NIOTSListenerBootstrap(group: NIOTSEventLoopGroup())
113+
.childChannelInitializer { channel in
114+
channel.configureHTTP2Pipeline(mode: .server) { channel in
115+
channel.pipeline.addHandlers([
116+
HTTP2FramePayloadToHTTPServerCodec(),
117+
ExampleChannelHandler()
118+
])
119+
}.map { _ in () }
120+
}
121+
.tlsOptions(tlsOptions)
122+
```
123+
124+
Our example channel implementation processes both `HTTPRequest` and `HTTPResponse` types:
125+
126+
```swift
127+
final class ExampleChannelHandler: ChannelDuplexHandler {
128+
typealias InboundIn = HTTPTypeServerRequestPart
129+
typealias OutboundOut = HTTPTypeServerResponsePart
130+
131+
func channelRead(context: ChannelHandlerContext, data: NIOAny) {
132+
switch unwrapInboundIn(data) {
133+
case .head(let request):
134+
// Handle request headers
135+
case .body(let body):
136+
// Handle request body
137+
case .end(let trailers):
138+
// Handle complete request
139+
let response = HTTPResponse(status: .ok)
140+
context.write(wrapOutboundOut(.head(response)), promise: nil)
141+
context.writeAndFlush(wrapOutboundOut(.end(nil)), promise: nil)
142+
}
143+
}
144+
}
145+
```
146+
147+
## Request and Response Body
148+
149+
HTTP request and response bodies are not currently part of this package.
150+
151+
Please continue to use existing the mechanisms: `Data` and `InputStream` for Foundation and `ByteBuffer` for SwiftNIO.
152+
153+
We are interested in exploring proposals with the community to provide body handling in the future.
154+
155+
## Get Involved
156+
157+
The experience and expertise from this community is invaluable in creating the building blocks for a great HTTP experience in Swift.
158+
159+
The version of Swift HTTP Types we're releasing today is a starting point for feedback and discussion with the community.
160+
161+
You can get started by:
162+
163+
* Trying out the [swift-http-types package](https://github.com/apple/swift-http-types)
164+
* Participating in discussions with the [#http tag on the Swift forums](https://forums.swift.org/tag/http)
165+
* Opening [issues and contributing](https://github.com/apple/swift-http-types/issues) for any problems you find
166+
167+
We're looking forward to exploring the future of HTTP in Swift together.

0 commit comments

Comments
 (0)