SwiftUIからモックサーバーにPOSTする
Overview
SwiftUIのCombineを使用して、モックサーバーにHTTP POSTをおこないREST APIと通信する仕組みについて学んで、API通信ってどんな感じなのかイメージできるような記事を書きたかったので書いてみることにしました。FlutterとReactで経験あるので、仕組みさえ理解すればすぐに機能は実装できました。
summary
Node.jsが必要なので、インストールしておいてください。
今回はこちらのnpmのパッケージを使用します。
- プロジェクトを作成する
お好きなところに、プロジェクトフォルダを作成して、その中にjson-serverをインストールして、db.jsonを作成してください。
mkdir mock-server
cd mock-server
GithubのReadmeの通りに進めていけば環境構築はできます。こちらを参考に今回は、ダミーのデータを入れたBookListSampleを作成いたしました。
- パッケージをインストール
npm install -g json-server
- db.jsonを作成する
touch db.json
空っぽの配列のJSONを作っておきます。
{
"bookList": [
]
}
- サーバーを起動する
json-server --watch db.json
- こちらの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しか、知らない人是非是非試してみてください。
完成品のソースコード
Discussion