Name:
interface
Value:
Amplify has re-imagined the way frontend developers build fullstack applications. Develop and deploy without the hassle.

クイックスタート

前提条件

始める前に、以下がインストールされていることを確認してください:

新規に始める場合
XCode プロジェクトを作成する

Xcode を開き、Create New Project... を選択します。

Shows the Xcode starter video to start project

次のステップで iOSApp テンプレートを選択します。次へをクリックします。

Shows the template of apps for iOS

次の手順は:

  • Product Name(例:MyAmplifyApp)を追加する
  • Team(例:None)を選択する
  • Organization Identifier(例:com.example)を選択する
  • Interface として SwiftUI を選択する
  • Next を押す

Shows the project details dialog

これでプロジェクトが作成されます。

Shows the base project for SwiftUI

バックエンドの作成

AWS Amplify を始める最も簡単な方法は、create-amplify コマンドを使用して npm 経由で行うことです。ベースプロジェクトディレクトリから実行できます。

Terminal
cd my_amplify_app
npm 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 の開発者ごとのクラウドサンドボックスを使用します。この機能はチームの各開発者に個別のバックエンド環境を提供し、ローカル開発とテストに最適です。サンドボックス環境でアプリケーションを実行するには、以下のコマンドを実行します:

Terminal
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... を選択して以下の依存関係を追加します:

Shows the Amplify library for Swift

Shows the Amplify library for Swift

Shows the Amplify library for Swift

MyAmplifyAppApp クラスを以下のコードで更新します:

import Amplify
import Authenticator
import AWSCognitoAuthPlugin
import SwiftUI
@main
struct 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 Amplify
import 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 スキーマからモデルクラスを生成します:

Terminal
npx ampx generate graphql-client-code --format modelgen --model-target swift

生成されたファイルをプロジェクトに移動します。ファイルをプロジェクトにドラッグアンドドロップすることで行えます。

Shows the drag and drop phase

完了したら、API 依存関係をプロジェクトに追加します。File > Add Package Dependencies... を選択して AWSAPIPlugin を追加します。

Shows the Amplify API library for Swift selected

依存関係を追加したら、MyAmplifyAppApp.swift ファイルの import 部分を以下のコードで更新します:

MyAmplifyAppApp.swift
import Amplify
import AWSCognitoAuthPlugin
import AWSAPIPlugin

次に、MyAmplifyAppApp.swift ファイルの init() 部分を以下のコードで更新します:

MyAmplifyAppApp.swift
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 関数を追加します:

TodoViewModel.swift
import Amplify
import SwiftUI
@MainActor
class 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.swiftlistTodos 関数を更新して To-do アイテムをリスト表示します:

TodoViewModel.swift
@MainActor
class 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 を以下のコードで更新します:

ContentView.swift
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")
}
}
}
}

Swift の実装全体で async/await パターンが使用されており、簡単に使用するために Task 構造体を活用しています。Task 構造体の詳細については、ドキュメントを確認してください。

このコードは Todo を作成し、Todo が作成されるたびに Todo リストを更新します。

次のステップは todos の更新と削除です。そのために、TodoViewModel.swift ファイルに以下のコードで updateTododeleteTodo 関数を作成します:

TodoViewModel.swift
@MainActor
class 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:) を呼び出すようにします。

ContentView.swift
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 という新しいファイルを作成します:

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 の仕組みの概念ガイドをご覧ください。