Swift HTTP Typesなるものができたらしい

# はじめに
2023/7/10にSwift Http Typesなるものができました
本記事では公式ドキュメントの要約とその詳細について執筆していきます。

https://www.swift.org/blog/introducing-swift-http-types/


https://github.com/apple/swift-http-types

# Swift HTTP Typeでできること
さきにまとめを書いておきます。

- Swift HTTP TypesではNIOでのURL SessionやFoundationでのHTTPリクエスト、レスポンスといったことが可能
- 複数フレームワークを使用せずにHTTP通信のやりとりを行えるため、複数フレームワーク間で変換するコストが削減される。
- HTTP/1.1、HTTP/2、HTTP/3に対応
- Foundation、Swift NIOとの連携可能

# Swift HTTP Typesとは

Swift HTTP typesはHTTPメッセージの構成要素と共通表現について提供するものである。
HTTP RequestとHTTP Responseはクライアント、サーバの両方のユースケースのHTTPメッセージを表している。
複数のプロジェクトでこれを採用することで、より多くのクライアントとサーバ間で共有できるようになり、複数のフレームワークを使用する場合にタイプ間で変換するコストが削減される。

これらの型はHTTP/3やHTTP/2との互換性はもちろん、HTTP/1.1との互換性も維持している。

このパッケージの目標として、SwiftNIOのHTTP requestやHTTP response、FoundationのURL RequestやURL Responseに代わるものとなることを目指す。

このパッケージではあらゆるHTTP通信に適するように設計されており、既存のフレームワークに関連付けられていないため、重複したHTTP抽象化の必要がなくなる。

# 使用例

HTTPリクエストの核はメソッド、スキーム、権限、パスで構成されている。
``` swift
let request = HTTPRequest(method: .get, scheme: "https", authority: "www.example.com", path: "/")
```

FoundationのURLから同じリクエストを作成することもできる
``` swift
var request = HTTPRequest(method: .get, url: URL(string: "https://www.example.com/")!)
```

メソッドやプロパティは後からでも変更可能
``` swift
request.method = .post
request.path = "/upload"
```

レスポンスの作成も容易に可能
``` swift
let response = HTTPResponse(status: .ok)
```

プロパティを使用してヘッダーフィールドにアクセスし、変更もできる
``` swift
request.headerFields[.userAgent] = "MyApp/1.0"
```

共通のヘッダーフィールドが組み込まれており、カスタムヘッダーフィールドと値の拡張を簡単にできるため、ビジネスロジックな場面でも容易に使用できる
``` swift
extension HTTPField.Name {
    static let myCustomHeader = Self("My-Custom-Header")!
}

request.headerFields[.myCustomHeader] = "custom-value"
```

配列に入った値からもヘッダーフィールドを直接設定できる
``` swift
request.headerFields[raw: .acceptLanguage] = ["en-US", "zh-Hans-CN"]
```

ヘッダーフィールドへのアクセスもほぼ同じで、システム定義のフィールド、または独自の拡張機能を使用できる
``` swift
request.headerFields[.userAgent] // "MyApp/1.0"
request.headerFields[.myCustomHeader] // "custom-value"

request.headerFields[.acceptLanguage] // "en-US, zh-Hans-CN"
request.headerFields[raw: .acceptLanguage] // ["en-US", "zh-Hans-CN"]
```

# Foundationとの連携
URL Sessionを使用すると、“www.example.com”にPOSTでリクエストするための新たなHTTP Requestを作成することも容易である。
このリクエストの"User-Agent"ヘッダーフィールドを設定することはとても直感的なものであり、type systemによる自動補完を提供する。

``` swift
var request = HTTPRequest(method: .post, url: URL(string: "https://www.example.com/upload")!)
request.headerFields[.userAgent] = "MyApp/1.0"
let (responseBody, response) = try await URLSession.shared.upload(for: request, from: requestBody)
guard response.status == .created else {
    // Handle error
}
```

# Swift NIOとの連携

Swift NIOとの統合は、このパッケージが安定バージョンになると、[swift-nio-extras](https://github.com/apple/swift-nio-extras)パッケージで利用できるようになる。
新しいHTTPタイプで使用するNIOチャンネルハンドラーを構成するには、他のチャンネルハンドラーの前に"HTTP2FramePayloadToHTTPServerCodec"を追加する。

``` swift
NIOTSListenerBootstrap(group: NIOTSEventLoopGroup())
    .childChannelInitializer { channel in
        channel.configureHTTP2Pipeline(mode: .server) { channel in
            channel.pipeline.addHandlers([
                HTTP2FramePayloadToHTTPServerCodec(),
                ExampleChannelHandler()
            ])
        }.map { _ in () }
    }
    .tlsOptions(tlsOptions)
```

この例のチャンネル実装では、HTTP requestとHTTP responseの両方のタイプを処理する。

``` swift
final class ExampleChannelHandler: ChannelDuplexHandler {
    typealias InboundIn = HTTPTypeServerRequestPart
    typealias OutboundOut = HTTPTypeServerResponsePart

    func channelRead(context: ChannelHandlerContext, data: NIOAny) {
        switch unwrapInboundIn(data) {
        case .head(let request):
            // Handle request headers
        case .body(let body):
            // Handle request body
        case .end(let trailers):
            // Handle complete request
            let response = HTTPResponse(status: .ok)
            context.write(wrapOutboundOut(.head(response)), promise: nil)
            context.writeAndFlush(wrapOutboundOut(.end(nil)), promise: nil)
        }
    }
}

```

# まとめ
- Swift HTTP TypesではNIOでのURL SessionやFoundationでのHTTPリクエスト、レスポンスといったことが可能
- 複数フレームワークを使用せずにHTTP通信のやりとりを行えるため、複数フレームワーク間で変換するコストが削減される。
- HTTP/1.1、HTTP/2、HTTP/3に対応
- Foundation、Swift NIOとの連携可能

これを使うことで、いままでより高速なHTTP通信を実現することが出来るかもですね。
いつかFoundation、Swift NIOとの速度比較なども行ってみようと思います。
では、読んでくれてありがとうございました！