📚

SwiftUIからモックサーバーにPOSTする

2023/11/11に公開

Overview

SwiftUIのCombineを使用して、モックサーバーにHTTP POSTをおこないREST APIと通信する仕組みについて学んで、API通信ってどんな感じなのかイメージできるような記事を書きたかったので書いてみることにしました。FlutterとReactで経験あるので、仕組みさえ理解すればすぐに機能は実装できました。

summary

Node.jsが必要なので、インストールしておいてください。
https://nodejs.org/en

今回はこちらのnpmのパッケージを使用します。
https://github.com/typicode/json-server

  1. プロジェクトを作成する
    お好きなところに、プロジェクトフォルダを作成して、その中にjson-serverをインストールして、db.jsonを作成してください。
mkdir mock-server
cd mock-server

GithubのReadmeの通りに進めていけば環境構築はできます。こちらを参考に今回は、ダミーのデータを入れたBookListSampleを作成いたしました。

  1. パッケージをインストール
npm install -g json-server
  1. db.jsonを作成する
touch db.json

空っぽの配列のJSONを作っておきます。

{
  "bookList": [
    
  ]
}

  1. サーバーを起動する
json-server --watch db.json
  1. こちらのURLへアクセスして、自作したAPIがJSON形式で表示されたら成功です!
    http://localhost:3000/bookList/

SwiftUIのプロジェクトを作成する

今回は、作成したプロジェクトでMVVMぽいやつを作ってビルドして、入力フォームからデータをサーバー側に送信する機能を作成いたしました。

まずは、モデルとなる構造体を作ります。DartやKotlinでいうところのクラスですね。

import Foundation

struct Book: Codable {
    var title: String
    var author: String

    enum CodingKeys: String, CodingKey {
        case title = "title"
        case author = "Author"
    }
}

次は、Combineを使用するViewModelを作成します。これが、ViewとModelの橋渡しをしてくれます。

import Combine
import Foundation

class BookViewModel: ObservableObject {
    var cancellables = Set<AnyCancellable>()

    func postBook(book: Book) {
        guard let url = URL(string: "http://localhost:3000/bookList") else {
            print("Invalid URL")
            return
        }

        var request = URLRequest(url: url)
        request.httpMethod = "POST"
        request.setValue("application/json", forHTTPHeaderField: "Content-Type")

        do {
            request.httpBody = try JSONEncoder().encode(book)
        } catch {
            print("Failed to encode book")
            return
        }

        URLSession.shared.dataTaskPublisher(for: request)
            .map(\.data)
            .decode(type: [String: Book].self, decoder: JSONDecoder())
            .sink(receiveCompletion: { completion in
                switch completion {
                case .finished:
                    break
                case .failure(let error):
                    print("Error: \(error)")
                }
            }, receiveValue: { response in
                print("Success: \(response)")
            })
            .store(in: &cancellables)
    }

}

サーバー側にデータを送信する入力フォームを作成します。本のタイトルと、本の著者を入力する機能となっております。今回はエラーハンドリングとかはしてないです💦
そもそもモックだから、いるのか...
いや、サーバーが落ちてたらダイアログぐらいは出さないと!!!!

import SwiftUI

struct ContentView: View {
    @State private var title = ""
    @State private var author = ""
    @ObservedObject var viewModel = BookViewModel()

    var body: some View {
        VStack {
            TextField("Title", text: $title)
                .textFieldStyle(RoundedBorderTextFieldStyle())
                .padding()

            TextField("Author", text: $author)
                .textFieldStyle(RoundedBorderTextFieldStyle())
                .padding()

            Button("Save") {
                let book = Book(title: title, author: author)
                viewModel.postBook(book: book)
            }
            .padding()
        }
    }
}

プロジェクトを作成したときは、デフォルトのファイルで、ContentViewというstructをビルドするので、特に設定はいらないです。

import SwiftUI

@main
struct RestAPIApp: App {
    var body: some Scene {
        WindowGroup {
            ContentView()
        }
    }
}

それでは、データをPOSTしてみましょう!
2回ぐらいやってみるかな。画面のスクショだけだと、真っ白になってしまった😅

こんな感じで、JSONのデータを保存することができました!

thoughts

いかがでしたでしょうか?
自分でサーバーを構築するのは大変ですよね。
私は、簡易的なものを作れるんですけどモックサーバーを使った方が、REST APIと通信するのを体験するのには、十分な体験ができるので、無理して構築する手間を省くことができます💡
iOSしか、知らない人是非是非試してみてください。

完成品のソースコード
https://github.com/sakurakotubaki/SwiftUIPostApp

Jboy王国メディア

Discussion