LoginSignup
6
3

標準とswift-http-typesでAPIコール処理を書き比べてみる(Swift)

Last updated at Posted at 2023-08-12

はじめに

先日Appleから Swift HTTP Types が公開されました。
せっかくなので、APIコール処理を標準と書き比べてみます。

環境

  • OS:macOS Ventura 13.4.1
  • Swift:5.8
  • swift-http-types:0.2.1

前回の記事と同様、APIからディズニーランドの住所を取得して構造体に格納します。
http://zipcloud.ibsnet.co.jp/api/search?zipcode=2790031

実装を比べてみる

標準とswift-http-typesで実装を比べてみます。

共通処理

両方で使う共通の処理です。

構造体

取得する住所を格納する構造体です。

前回の記事 の構造体をほぼそのまま流用します。

Address.swift
struct Address: Decodable {
    var results: [Result]
    
    struct Result: Decodable, Identifiable {
        let id = UUID()
        var address1: String
        var address2: String
        var address3: String
        var kana1: String
        var kana2: String
        var kana3: String
    }
}

ResultForEach でループさせたいため、警告が発生しますが雑に Identifiable へ準拠させています。

UI

SwiftUIでViewを実装し、 .task() で住所を取得して表示します。

ContentView.swift
import SwiftUI

struct ContentView: View {
    @State private var address: Address?
    
    var body: some View {
        ForEach(address?.results ?? []) { result in
            VStack(alignment: .leading) {
                Text(result.kana1 + result.kana2 + result.kana3)
                Text(result.address1 + result.address2 + result.address3)
            }
            .font(.title)
        }
        .task {
            await getAddress(zipCode: "2790031")            
        }
    }
    
    private func getAddress(zipCode: String) async {
        // TODO: 住所を取得して `address` に格納する
    }

標準

標準の URLSession を使った実装です。
前回と異なり、非同期の data(for:) メソッドを使います。

ContentView.swift
import Foundation

// ...

    private func getAddress(zipCode: String) async {
        let baseUrlString = "http://zipcloud.ibsnet.co.jp"
        let searchPath = "/api/search"
        let searchUrl = URL(string: baseUrlString + searchPath)!
        guard var components = URLComponents(url: searchUrl, resolvingAgainstBaseURL: searchUrl.baseURL != nil) else {
            return
        }
        components.queryItems = [
            .init(name: "zipcode", value: zipCode),
        ] + (components.queryItems ?? [])
        var request = URLRequest(url: components.url!)
        request.httpMethod = "GET"
        request.addValue("application/json", forHTTPHeaderField: "Content-Type")
        
        do {
            let (data, response) = try await URLSession.shared.data(for: request)
            guard let response = response as? HTTPURLResponse,
                  response.statusCode == 200 else {
                return
            }
            
            self.address = try JSONDecoder().decode(Address.self, from: data)
        } catch {
            print("Error: \(error)")            
        }
    }

URLRequest の生成部分は前回と変わりませんが、APIコール部分が非同期でスッキリ書けました。

非同期処理が完了すると、住所が表示されることも確認できました。
スクリーンショット 2023-08-12 19.38.59.png

Swift HTTP Types

続いてSwift HTTP Typesを使った実装です。

import HTTPTypes
import HTTPTypesFoundation

// ...

    private func getAddress(zipCode: String) async {
        let baseUrlString = "http://zipcloud.ibsnet.co.jp"
        var request = HTTPRequest(url: URL(string: baseUrlString)!)
        request.method = .get
        request.path = "/api/search?zipcode=\(zipCode)"
        request.headerFields[.contentType] = "application/json"
        
        do {
            let (data, response) = try await URLSession.shared.data(for: request)
            guard response.status == .ok else {
                return
            }
            
            self.address = try JSONDecoder().decode(Address.self, from: data)
        } catch {
            print("Error: \(error)")            
        }
    }

URLSessionを使う部分は標準と同様ですが、HTTP周りを型安全に扱えるのが優れています。
URLSessionの代わりに SwiftNIO を使うこともできます。

クエリストリングを簡単に扱う方法は用意されていない 1 ので、 path にそのまま含めています。

おわりに

Swift HTTP Typesを使うことで、HTTP周りを型安全に扱えることがわかりました。
Alamofire のようなサードパーティ製のライブラリを使っていない場合、積極的に導入してよさそうです。

ただまだ正式リリースはされていないので、それまでは導入を待ったほうがいいかもしれません。

  1. https://github.com/apple/swift-http-types/issues/19

6
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
3