クイックスタート
前提条件
始める前に、以下がインストールされていることを確認してください:
- Node.js v18.17 以降
- npm v9 以降
- git v2.14.1 以降
- AWS アカウントの作成も必要です。AWS Amplify は AWS 無料利用枠の一部であることに注意してください。
- Amplify で使用するための AWS アカウントの設定 手順。
- マシンに Xcode と Developer Tooling がインストールされている必要があります。
新規に始める場合XCode プロジェクトを作成する
Xcode を開き、Create New Project... を選択します。
次のステップで iOS の App テンプレートを選択します。次へをクリックします。
次の手順は:
- Product Name(例:MyAmplifyApp)を追加する
- Team(例:None)を選択する
- Organization Identifier(例:com.example)を選択する
- Interface として SwiftUI を選択する
- Next を押す
これでプロジェクトが作成されます。
バックエンドの作成
AWS Amplify を始める最も簡単な方法は、create-amplify コマンドを使用して npm 経由で行うことです。ベースプロジェクトディレクトリから実行できます。
cd my_amplify_appnpm create amplify@latest? Where should we create your project? (.) # press enterこのコマンドを実行すると、現在のプロジェクトに Amplify バックエンドファイルが以下のファイル構成でscaffold されます:
├── amplify/│ ├── auth/│ │ └── resource.ts│ ├── data/│ │ └── resource.ts│ ├── backend.ts│ └── package.json├── node_modules/├── .gitignore├── package-lock.json├── package.json└── tsconfig.jsonバックエンドをデプロイするには、Amplify の開発者ごとのクラウドサンドボックスを使用します。この機能はチームの各開発者に個別のバックエンド環境を提供し、ローカル開発とテストに最適です。サンドボックス環境でアプリケーションを実行するには、以下のコマンドを実行します:
npx ampx sandboxサンドボックス環境がデプロイされると、amplify_outputs.json が作成されます。ただし、Xcode はそれらを認識できません。ファイルを認識させるには、生成されたファイルをプロジェクトにドラッグアンドドロップする必要があります。
認証の追加
初期のscaffoldには、amplify/auth/resource.ts ファイルに事前設定済みの認証バックエンドがすでに定義されています。メールアドレスとパスワードによるログインをサポートするように設定されていますが、Google、Amazon、Sign In With Apple、Facebook など、さまざまなログインメカニズムをサポートするように拡張できます。
ログイン体験を素早く起動する最も簡単な方法は、Amplify UI ライブラリで利用可能な Authenticator UI コンポーネントを使用することです。
Authenticator を使用するには、Xcode でプロジェクトを開き、File > Add Packages... を選択して以下の依存関係を追加します:
-
Amplify Library for Swift: GitHub URL(https://github.com/aws-amplify/amplify-swift)を入力し、**Up to Next Major Version** を選択して Add Package Dependencies... をクリックし、以下のライブラリを選択します:
- Amplify
- AWSCognitoAuthPlugin
- Amplify UI Swift - Authenticator: GitHub URL(https://github.com/aws-amplify/amplify-ui-swift-authenticator)を入力し、**Up to Next Major Version** を選択して Add Package Dependencies... をクリックし、以下のライブラリを選択します:
- Authenticator
MyAmplifyAppApp クラスを以下のコードで更新します:
import Amplifyimport Authenticatorimport AWSCognitoAuthPluginimport SwiftUI
@mainstruct MyApp: App { init() { do { try Amplify.add(plugin: AWSCognitoAuthPlugin()) try Amplify.configure(with: .amplifyOutputs) } catch { print("Unable to configure Amplify \(error)") } }
var body: some Scene { WindowGroup { ContentView() } }}ContentView を以下のコードで更新します:
import Amplifyimport Authenticator
struct ContentView: View { var body: some View { Authenticator { state in VStack { Button("Sign out") { Task { await state.signOut() } } } } }}Authenticator コンポーネントは認証バックエンドの設定を自動検出し、認証バックエンドの認証フローに基づいて正しい UI 状態をレンダリングします。
ローカル環境でアプリケーションを再度実行してみましょう。ログイン体験が表示されるはずです。
データの追加
初期のscaffoldには、amplify/data/resource.ts ファイルに事前設定済みのデータバックエンドがすでに定義されています。デフォルトの例では、content フィールドを持つ Todo モデルが作成されます。
以下を追加するように変更しましょう:
- ブール型の
isDoneフィールド。 - Auth リソースを通じて認証されたオーナーが自分のレコードを「作成」、「読み取り」、「更新」、「削除」できる認可ルール。
defaultAuthorizationModeを更新して、ユーザー認証トークンで API リクエストに署名します。
import { type ClientSchema, a, defineData } from '@aws-amplify/backend';
const schema = a.schema({ Todo: a .model({ content: a.string(), isDone: a.boolean().required() }) .authorization((allow) => [allow.owner()])});
export type Schema = ClientSchema<typeof schema>;
export const data = defineData({ schema, authorizationModes: { defaultAuthorizationMode: 'userPool' }});次に、To-do アイテムを作成、一覧表示、削除するための UI を実装しましょう。
Amplify はバックエンド API と対話するためのコードを自動的に生成できます。以下のコマンドで Data スキーマからモデルクラスを生成します:
npx ampx generate graphql-client-code --format modelgen --model-target swift生成されたファイルをプロジェクトに移動します。ファイルをプロジェクトにドラッグアンドドロップすることで行えます。
完了したら、API 依存関係をプロジェクトに追加します。File > Add Package Dependencies... を選択して AWSAPIPlugin を追加します。
依存関係を追加したら、MyAmplifyAppApp.swift ファイルの import 部分を以下のコードで更新します:
import Amplifyimport AWSCognitoAuthPluginimport AWSAPIPlugin次に、MyAmplifyAppApp.swift ファイルの init() 部分を以下のコードで更新します:
init() { do { try Amplify.add(plugin: AWSCognitoAuthPlugin()) try Amplify.add(plugin: AWSAPIPlugin(modelRegistration: AmplifyModels())) try Amplify.configure(with: .amplifyOutputs) } catch { print("Unable to configure Amplify \(error)") }}TodoViewModel.swift という新しいファイルを作成し、以下のコードで createTodo 関数を追加します:
import Amplifyimport SwiftUI
@MainActorclass TodoViewModel: ObservableObject { func createTodo() async { let creationTime = Temporal.DateTime.now() let todo = Todo( content: "Random Todo \(creationTime.iso8601String)", isDone: false, createdAt: creationTime, updatedAt: creationTime ) do { let result = try await Amplify.API.mutate(request: .create(todo)) switch result { case .success(let todo): print("Successfully created todo: \(todo)") todos.append(todo) case .failure(let error): print("Got failed result with \(error.errorDescription)") } } catch let error as APIError { print("Failed to create todo: ", error) } catch { print("Unexpected error: \(error)") } }}上記のコードは現在の時刻でランダムな Todo を作成します。
次に、TodoViewModel.swift の listTodos 関数を更新して To-do アイテムをリスト表示します:
@MainActorclass TodoViewModel: ObservableObject { @Published var todos: [Todo] = []
func createTodo() { /// ... }
func listTodos() async { let request = GraphQLRequest<Todo>.list(Todo.self) do { let result = try await Amplify.API.query(request: request) switch result { case .success(let todos): print("Successfully retrieved list of todos: \(todos)") self.todos = todos.elements case .failure(let error): print("Got failed result with \(error.errorDescription)") } } catch let error as APIError { print("Failed to query list of todos: ", error) } catch { print("Unexpected error: \(error)") } }}これにより取得した todos の値が Published オブジェクトに代入されます。
次に、todos を監視するように UI コードを更新しましょう。ContentView.swift ファイルの VStack を以下のコードで更新します:
struct ContentView: View {
// Create an observable object instance. @StateObject var vm = TodoViewModel()
var body: some View { Authenticator { state in VStack { Button("Sign out") { Task { await state.signOut() } } Button(action: { Task { await vm.createTodo() } }) { HStack { Text("Add a New Todo") Image(systemName: "plus") } } .accessibilityLabel("New Todo") } } }}このコードは Todo を作成し、Todo が作成されるたびに Todo リストを更新します。
次のステップは todos の更新と削除です。そのために、TodoViewModel.swift ファイルに以下のコードで updateTodo と deleteTodo 関数を作成します:
@MainActorclass TodoViewModel: ObservableObject { @Published var todos: [Todo] = []
func createTodo() { // ... }
func listTodos() { // ... }
func deleteTodos(indexSet: IndexSet) async { for index in indexSet { do { let todo = todos[index] let result = try await Amplify.API.mutate(request: .delete(todo)) switch result { case .success(let todo): print("Successfully deleted todo: \(todo)") todos.remove(at: index) case .failure(let error): print("Got failed result with \(error.errorDescription)") } } catch let error as APIError { print("Failed to deleted todo: ", error) } catch { print("Unexpected error: \(error)") } } }
func updateTodo(todo: Todo) async { do { let result = try await Amplify.API.mutate(request: .update(todo)) switch result { case .success(let todo): print("Successfully updated todo: \(todo)") case .failure(let error): print("Got failed result with \(error.errorDescription)") } } catch let error as APIError { print("Failed to updated todo: ", error) } catch { print("Unexpected error: \(error)") } }}ContentView.swift ファイルの List を更新して、View が表示されたときに todos を取得し、ユーザーが todo を左スワイプしたときに deleteTodos(indexSet:) を呼び出すようにします。
struct ContentView: View { @StateObject var vm = TodoViewModel()
var body: some View { Authenticator { state in VStack { // ... Sign out Button List { ForEach($vm.todos, id: \.id) { todo in TodoRow(vm: vm, todo: todo) } .onDelete { indexSet in Task { await vm.deleteTodos(indexSet: indexSet) } } } .task { await vm.listTodos() } // ... Add new Todo button } } }}最後に、以下のコードで TodoRow.swift という新しいファイルを作成します:
import SwiftUI
struct TodoRow: View { @ObservedObject var vm: TodoViewModel @Binding var todo: Todo
var body: some View { Toggle(isOn: $todo.isDone) { Text(todo.content ?? "") } .toggleStyle(.switch) .onChange(of: todo.isDone) { _, newValue in var updatedTodo = todo updatedTodo.isDone = newValue Task { await vm.updateTodo(todo: updatedTodo) } } }}
#Preview { @State var todo = Todo(content: "Hello Todo World 20240706T15:23:42.256Z", isDone: false) return TodoRow(vm: TodoViewModel(), todo: $todo)}これにより、todo の isDone を更新するトグルと、todo を削除するスワイプが UI に表示されます。アプリケーションを実行すると、以下のフローが表示されるはずです。
プロジェクトのクリーンアップのためにサンドボックス環境を終了できます。
クラウドへの変更の公開
クラウドへの変更の公開にはリモート git リポジトリが必要です。Amplify はフルスタックブランチデプロイメントを提供しており、フィーチャーブランチからインフラストラクチャとアプリケーションコードの変更を自動的にデプロイできます。詳細については、フルスタックブランチデプロイメントガイドをご覧ください。
🥳 成功
以上です!AWS Amplify でフルスタックアプリの構築に成功しました。Amplify の使い方についてさらに詳しく学びたい場合は、Amplify の仕組みの概念ガイドをご覧ください。