# Data — Mobile ## Prerequisites Initialize Amplify with Auth and API plugins before using this feature: **Flutter** — `lib/main.dart`: ```dart await Amplify.addPlugins([AmplifyAuthCognito(), AmplifyAPI()]); await Amplify.configure(amplifyConfig); ``` > Generate dart outputs: `npx ampx sandbox --outputs-format dart --outputs-out-dir lib` **Swift (Apple platforms):** ```swift try Amplify.add(plugin: AWSCognitoAuthPlugin()) try Amplify.add(plugin: AWSAPIPlugin()) try Amplify.configure(with: .amplifyOutputs) ``` > Drag `amplify_outputs.json` into the Xcode project navigator so it is included in the app bundle. **Android:** ```kotlin Amplify.addPlugin(AWSCognitoAuthPlugin()) Amplify.addPlugin(AWSApiPlugin()) Amplify.configure(AmplifyOutputs(R.raw.amplify_outputs), applicationContext) ``` > Place `amplify_outputs.json` in `app/src/main/res/raw/`. Enable core library desugaring for API level < 26. > > **Backend required:** Data must be defined in `amplify/data/resource.ts` > using `defineData` — see [data-backend.md](data-backend.md). ## Flutter Import `package:amplify_flutter/amplify_flutter.dart`. All operations go through `Amplify.API`. **Queries:** `Amplify.API.query(request: ModelQueries.list(Todo.classType))` — response in `.response.data?.items`. Same pattern for `.get()`. **Mutations:** `Amplify.API.mutate(request: ModelMutations.create(todo))` — same shape for `.update()`, `.delete()`. Build updated models with `todo.copyWith(done: true)`. **Subscriptions:** `Amplify.API.subscribe(ModelSubscriptions.onCreate(Todo.classType))` → returns a stream. Listen with `.listen()`, cancel with `sub.cancel()`. ## Swift (Apple platforms) > Supported: iOS 13+, macOS 12+, tvOS 13+, watchOS 9+, visionOS 1+ (preview). Uses `Amplify.API.query/mutate` with async/await. Swift uses shorthand request builders (`.list()`, `.create()`, `.subscription(of:type:)`) via `GraphQLRequest` extensions, unlike Flutter's explicit `ModelQueries`/`ModelMutations` classes. **Queries:** `try await Amplify.API.query(request: .list(Todo.self))` — result is `.success(let todos)`. **Mutations:** `try await Amplify.API.mutate(request: .create(newTodo))` — same for `.update()`, `.delete()`. Modify models directly: `updated.done = true`. **Subscriptions:** `Amplify.API.subscribe(request: .subscription(of: Todo.self, type: .onCreate))` → use `for try await event in subscription`. Cancel via `task.cancel()` when the view disappears. ## Android (Kotlin) Android supports both callback-based and coroutine-based APIs. Coroutine example (recommended): **Queries:** ```kotlin suspend fun getTodo(id: String) { try { val response = Amplify.API.query(ModelQuery.get(Todo::class.java, id)) Log.i("MyAmplifyApp", response.data.name) } catch (error: ApiException) { Log.e("MyAmplifyApp", "Query failed", error) } } ``` **Mutations:** ```kotlin val todo = Todo.builder() .name("My todo") .build() try { val response = Amplify.API.mutate(ModelMutation.create(todo)) Log.i("MyAmplifyApp", "Todo with id: ${response.data.id}") } catch (error: ApiException) { Log.e("MyAmplifyApp", "Create failed", error) } ``` Same pattern for `.update()` and `.delete()`. Build models via `Todo.builder().name("text").build()`; update via `todo.copyOfBuilder().done(true).build()`. **Subscriptions (coroutine — uses Kotlin Flow):** ```kotlin val job = scope.launch { try { Amplify.API.subscribe(ModelSubscription.onCreate(Todo::class.java)) .catch { Log.e("MyAmplifyApp", "Error on subscription", it) } .collect { Log.i("MyAmplifyApp", "Todo created: ${it.data.name}") } } catch (error: ApiException) { Log.e("MyAmplifyApp", "Subscription not established", error) } } // When done: job.cancel() ``` **Callback alternative:** all operations also accept `onSuccess`/`onError` lambdas — e.g. `Amplify.API.query(ModelQuery.list(Todo::class.java), { response -> ... }, { error -> ... })`. ## Pitfalls - **Missing codegen for native platforms:** Flutter, Swift, and Android run `npx ampx generate graphql-client-code` to produce typed model classes. Without this step, model types do not exist. - **GraphQL vs REST confusion:** All data operations use the GraphQL API (`Amplify.API.query`/`mutate`), not REST. Using REST methods for model CRUD returns errors. - **Subscription cleanup:** Every platform requires explicit subscription cleanup (`.cancel()` on Swift tasks, `job.cancel()` for Kotlin coroutines, `subscription.cancel()` for callbacks, or `sub.cancel()` for Flutter) — missing cleanup causes connection leaks and stale data. - **Offline sync (Flutter/Swift/Android):** DataStore is a separate API from direct API operations. Do not mix `DataStore.query()` with `Amplify.API.query()` in the same model workflow. ## Links - [Data Overview (Android)](https://docs.amplify.aws/android/build-a-backend/data/) - [Set Up Data (Android)](https://docs.amplify.aws/android/build-a-backend/data/set-up-data/) - [Connect to Existing Data Sources (Android)](https://docs.amplify.aws/android/build-a-backend/data/connect-to-existing-data-sources/) - [Data Client (Android)](https://docs.amplify.aws/android/frontend/data/) - [Data Overview (Swift)](https://docs.amplify.aws/swift/build-a-backend/data/) - [Set Up Data (Swift)](https://docs.amplify.aws/swift/build-a-backend/data/set-up-data/) - [Connect to Existing Data Sources (Swift)](https://docs.amplify.aws/swift/build-a-backend/data/connect-to-existing-data-sources/) - [Data Client (Swift)](https://docs.amplify.aws/swift/frontend/data/) - [Data Overview (Flutter)](https://docs.amplify.aws/flutter/build-a-backend/data/) - [Set Up Data (Flutter)](https://docs.amplify.aws/flutter/build-a-backend/data/set-up-data/) - [Connect to Existing Data Sources (Flutter)](https://docs.amplify.aws/flutter/build-a-backend/data/connect-to-existing-data-sources/) - [Data Client (Flutter)](https://docs.amplify.aws/flutter/frontend/data/)