0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

自作のiPhoneアプリとRenderで通信してみる

Posted at

概要

以前、iPhoneアプリを作成しました
RenderというサービスでFast APIを構築しました

ということはアプリとAPIサーバーで通信が可能にできるのではと思ったので、試してみることにします

本題

作るものとしては自作アプリを開いて用意された2つのボタンを押すとGETリクエスト・POSTリクエストをrenderで用意したAPIに送るというようなものを想定しています

イメージ図

少し雑ですが3画面作る予定です
GET・POSTリクエスト後の画面からトップ画面に戻るボタンのようなものも作れると良いかもしれませんが、そこは努力目標とします

  • アプリトップ画面
    Untitled Diagram.drawio.png

  • GETリクエストボタン押下後
    Untitled Diagram.drawio (1).png

  • POSTリクエストボタン押下後
    Untitled Diagram.drawio.png

実装

画面の作成

とりあえず動きをつけたいということで、画面を3個分作成してボタンを押すと画面遷移ができる状態にしたいと思います

画面遷移ができる状態にする

大元となる「〜App」というディレクトリ直下に「〜App.swift」というファイルがあります

このファイルがアプリのエントリーポイントとなり、ナビゲーション構造を管理するコンポーネントとなっています
今回、画面の遷移を実装したいので「NavigationStack」というものを使用して遷移ができるようにします

サンプルコードとしては以下になります
ContentViewの部分がアプリ起動時に表示される画面です
(「ContentView.swift」というファイルが存在しており、そちらの担当になります)

HelloWorldApp.swift
import SwiftUI

@main
struct HelloWorldApp: App {
    var body: some Scene {
        WindowGroup {
            // アプリ全体のルートビューをNavigationStackで囲む
            NavigationStack {
                ContentView() // アプリが最初に表示する画面
            }
        }
    }
}

トップ画面の作成

画面遷移ができる状態になったので次はトップ画面を作成します

先ほどアプリ起動時のトップ画面はContentView.swiftに担当させたので、対象のファイルを修正します

ContentView.swift
import SwiftUI

struct ContentView: View {
    var body: some View {
        VStack {
            // 画面タイトル
            Text("Hello World").padding(.bottom, 50) // 下に余白
            
            // 遷移リンク (ボタンを押すと指定されたViewへ移動)
            // Destinationには、次に表示したいViewを指定します
            NavigationLink(destination: GetRequestView()) {
                Text("GETリクエスト")
                    .font(.headline)
                    .padding()
                    .background(Color.blue)
                    .foregroundColor(.white)
                    .cornerRadius(8)
            }.padding(.bottom, 50) // 下に余白
            
            NavigationLink(destination: PostRequestView()) {
                Text("POSTリクエスト")
                    .font(.headline)
                    .padding()
                    .background(Color.orange)
                    .foregroundColor(.white)
                    .cornerRadius(8)
            }

        }
        // NavigationStack内のViewにタイトルを設定
        .navigationTitle("ホーム")
    }
}

// プレビュー用のコード (画面の確認用)
#Preview {
    ContentView()
}

ざっとコードを貼りましたが、それぞれ次のような役割だと認識しています

  • Text
    • htmlで言うところの p タグ
  • NavigationLink
    • ここがボタン押下後にどうするかを決めるコードになります
    • destinationの後ろに遷移したい画面を管理しているファイル名・もしくはView名を記載します
  • #Preview
    • 言葉の通りXcode内でプレビューができるようにします

ここまでで作りたかった画面が3枚完成しています
(さらにトップ画面に戻るボタン?のようなものもできています)

とりあえずトップ画面をプレビューで表示した時の画像を貼ります

スクリーンショット 2025-10-02 23.27.48.png

GETリクエストのコード
GetRequest.swift
import SwiftUI

struct GetRequestView: View {
    var body: some View {
        VStack {
            Text("Postリクエストを送信しました")
                .font(.title2)
            
            // ここにロジックを実装
            
        }
        .padding()
        // この画面にもタイトルを設定できます
        .navigationTitle("Get")
    }
}

// プレビュー用のコード (画面の確認用)
#Preview {
    GetRequestView()
}
POSTリクエストのコード
GetRequest.swift
import SwiftUI

struct PostRequestView: View {
    var body: some View {
        VStack {
            Text("Postリクエストを送信しました")
                .font(.title2)
            
            // ここにロジックを実装
            
        }
        .padding()
        // この画面にもタイトルを設定できます
        .navigationTitle("Post")
    }
}

// プレビュー用のコード (画面の確認用)
#Preview {
    PostRequestView()
}

API側の実装

大きくは語りません
以下を参考にFast APIでレスポンスを返すようにしておきます

APIとの通信を実装

APIの準備も完了したので、ついにアプリとAPIの通信を実装してみます

iOS 15以降は、Swiftではasync/await構文を使用して非同期通信をより簡潔に記述することが推奨されていルトの忠告もありました

例としては以下のようなコード実装をするようです

sampleAPI.swift
func fetchDataAsync() async throws -> Data {
    guard let url = URL(string: "リクエストするURL") else {
        throw URLError(.badURL)
    }
    
    // try-awaitで、コールバックを使わずにデータとレスポンスを取得(ここでリクエストを送信)
    let (data, response) = try await URLSession.shared.data(from: url)
    
    guard let httpResponse = response as? HTTPURLResponse,
          (200...299).contains(httpResponse.statusCode) else {
        throw URLError(.badServerResponse)
    }
    
    return data
}

エラー処理はいろいろしなければいけないと思いますが、リクエストするURLにrenderで構築したAPIに向けたURL
を指定すればAPI通信ができるようになるといった手筈です

if let decodedString = String(data: data, encoding: .utf8) {
    await MainActor.run {
        self.message = "サーバーからの応答: \(decodedString)"
        self.errorMessage = nil // 成功したのでエラーをクリア
    }
} else {
    await MainActor.run {
        errorMessage = "応答データのデコードに失敗しました。"
        message = "" // エラーなのでメッセージはクリア
    }
}

今回は上記のようにしておいてGetリクエストで返却されたレスポンスデータを簡単に表示しています
Mac上でビルドしたあとのシミュレーターの画面になります

スクリーンショット 2025-10-03 0.31.32.png

Postの方は同じようにやれるはずなので、説明はスキップします

終わりに

ということで以上が一通りアプリとAPIの通信を行う流れでした
慣れるまではこの一連の繰り返しを行って習慣づけていくしかないのかなと思うことばかりでした

挫けずに継続していきたいと思います

0
0
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
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?