【Swift】POSTメソッドを使ってWebAPIを叩く方法

Web APIを叩くコードをよく忘れるのでここに書いておこうと思い投稿しました。

## 叩いてみよう

- コード全文はGithubにて公開しています([こちらにURL貼ってます](#コード全文))
- このコードをコピペし、`FIXME`の部分を修正すれば使用可能です
- `Response`や`HTTPBody`などはご自身で作成してください

``` Swift: APIClient.swift
struct APIClient {
    // FIXME: URLと取得したAPI Keyを入力してください
    private let urlString: String = ""
    private let apiKey: String = ""
    
    /// データを取得するメソッドです
    ///
    /// ## Return
    /// - `Response`: APIからのレスポンスを格納するStructです。
    /// - `Error`: 通信に失敗した場合などに返すエラーです
    func fetch() async -> Result<Response, Error> {
        do {
            // MARK: - 1.URLを作成する
            // String型で入力されたurlStringをURL型へ変換しています
            guard let url = URL(string: self.urlString) else {
                return .failure(CommunicationErrors.badURL)
            }
            
            // MARK: - 2.URLリクエストを作成する
            func createURLRequest() -> URLRequest {
                var urlRequest = URLRequest(url: url)
                // メソッドの指定(今回はPOSTメソッドを使用)
                urlRequest.httpMethod = "POST"
                
                // MARK: HTTPHeaderを付与する場合
                // FIXME: `["key": "value"]`の部分を使用するサービスが求めているものにしましょう
                // HTTPHeaderに記入する内容はリファレンスに書いてあるはずです
                urlRequest.allHTTPHeaderFields = ["key": "value"]
                
                // MARK: HTTPBodyを付与する場合
                // HTTPBodyも同様にサービスが求めているものを記入しましょう
                // このコードではStructをJSONへエンコードし、httpBodyへ記入しています
                var httpBody: Data? {
                    // FIXME: `HTTPBody()`の部分を変更してください
                    // HTTPBodyに記入する内容はリファレンスに書いてあるはずです
                    // `HTTPBody()`は作成したStructの名前です
                    let encodeValue = HTTPBody()
                    return try? JSONEncoder().encode(encodeValue)
                }
                urlRequest.httpBody = httpBody
                
                return urlRequest
            }
            
            // MARK: - 3.通信を行う
            guard let (data, urlRequest) = try? await URLSession.shared.data(for: createURLRequest()) else {
                return .failure(CommunicationErrors.couldNotCreateRequest)
            }
            
            // MARK: - 4.レスポンスを受け取る
            guard let response = urlRequest as? HTTPURLResponse else {
                return .failure(CommunicationErrors.responseNotReturned)
            }
            // ステータスコードを確認し正常に通信が行われたか確認する
            // ステータスコードが200番台ではなかった場合
            guard 200..<300 ~= response.statusCode else {
                return .failure(CommunicationErrors.badStatusCode(response.statusCode))
            }
            
            // MARK: - 5.JSONをStructへ変換する
            let decodeData = try JSONDecoder().decode(Response.self, from: data)
            return .success(decodeData)
        } catch {
            return .failure(error)
        }
    }
}

// MARK: - データ取得時に発生するエラーを分ける
enum CommunicationErrors: Error {
    case badURL
    case couldNotCreateRequest
    case responseNotReturned
    case badStatusCode(Int)
}
extension CommunicationErrors: LocalizedError {
    // エラーの説明文
    var errorDescription: String? {
        switch self {
        case .badURL:
            return "URLが不正です"
        case .couldNotCreateRequest:
            return "リクエストの作成に失敗しました"
        case .responseNotReturned:
            return "レスポンスがありませんでした"
        case .badStatusCode(let statusCode):
            return "通信ができませんでした statusCode: \(statusCode)"
        }
    }
}
```

## コード全文

こちらになります

https://github.com/cranoo3/URLSessionPOSTSample

## 参考にした記事等

- [【Swift】URLSessionクラスとは？URLRequestとHTTP通信！](https://appdev-room.com/swift-urlsession)
- [URLsessionを用いたHTTPリクエストの方法(Swift, Xcode)](https://qiita.com/shungo_m/items/64564fd822a7558ac7b1)
- [SwiftでのURL操作！完全ガイドのたった10の方法](https://jp-seemore.com/app/16084/#toc10)

## 最後に
最後までご覧いただきありがとうございます🙏
意見等ありましたらコメントいただけると幸いです
分からないことだらけなので、勉強の参考にさせてください😢