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

Page updated Aug 3, 2024

Maintenance ModeYou are viewing Amplify Gen 1 documentation. Amplify Gen 1 has entered maintenance mode and will reach end of life on May 1, 2027. New project should use Amplify Gen 2. For existing Gen 1 projects, a migration guide and tooling are available to help you upgrade. Switch to the latest Gen 2 docs →

CDKで構築された既存のAWSリソースに接続

このガイドでは、AWS Cloud Development Kit(AWS CDK)を使用して既に作成したAWSリソースに新しいアプリを接続する方法を説明します。AWS CDKは、最新のプログラミング言語を使用してクラウドインフラストラクチャをコードとして定義するためのオープンソースソフトウェア開発フレームワークです。このインフラストラクチャはAWS CloudFormationを通じてデプロイされます。

このガイドでは、Amplify Data CDKを使用してAWS AppSyncでGraphQL APIバックエンドを作成します。これはコアバックエンドを作成します。その後、FlutterアプリをビルドしてGraphQL APIと統合します。

開始する前に、以下のものが必要です:

  • AWSアカウント:まだアカウントを持っていない場合は、AWSEnvironmentのセットアップチュートリアルに従って、簡単な概要を確認してください。
  • Amplify CLIインストールおよび設定済み。
  • テキストエディタ。このガイドではVS Codeを使用しますが、任意のIDEを使用できます。
  • Flutter及びそのコマンドラインツールインストールおよび設定済み。

Amplify Data CDKコンストラクトを使用してGraphQL APIを構築

CDKは、コード内でクラウドインフラストラクチャを定義する簡単な方法を提供します。このセクションでは、CDKを使用して、アプリケーションのバックエンドリソースを構築します。

ステップ1: ターミナルで次のコマンドを実行して、CDKアプリ用のフォルダを作成します。

Terminal
mkdir cdk-backend

ステップ2: cdk-backendフォルダに移動し、cdk initコマンドを実行して新しいCDKプロジェクトを作成し、優先言語を指定します。

Terminal
cd cdk-backend
cdk init --language typescript

ステップ3: VS Codeまたは好みのIDEを使用して、新しく作成されたCDKプロジェクトを開きます。

ステップ4: ターミナルでcdk_backendルートフォルダに移動し、次のコマンドを実行してAWS Amplify Dataパッケージをインストールします。

Terminal
npm install @aws-amplify/data-construct

ステップ5: 次のコードに示すようにcdk_backend/lib/cdk-backend-stack.tsファイルを更新して、AmplifyDataコンストラクトを使用してAWS AppSync APIを作成します。

lib/cdk-backend-stack.ts
import * as cdk from 'aws-cdk-lib';
import { Construct } from 'constructs';
import {
AmplifyData,
AmplifyDataDefinition
} from '@aws-amplify/data-construct';
export class CdkBackendStack extends cdk.Stack {
constructor(scope: Construct, id: string, props?: cdk.StackProps) {
super(scope, id, props);
new AmplifyData(this, 'AmplifyCdkData', {
definition: AmplifyDataDefinition.fromString(/* GraphQL */ `
type Todo @model @auth(rules: [{ allow: public }]) {
id: ID!
name: String!
description: String
complete: Boolean
}
`),
authorizationModes: {
defaultAuthorizationMode: 'API_KEY',
apiKeyConfig: {
expires: cdk.Duration.days(30)
}
}
});
}
}

ステップ6: 次のコマンドを実行してCDKスタックをデプロイします。

cdk deploy

ステップ7: CDKがデプロイのリソースを準備し、次のプロンプトが表示されます。Yを入力してEnterキーを押します。

The CDK preparing for deployment.

CDKはスタックをデプロイし、次の確認を表示します。デプロイされたAPIの詳細に注意してください。次のセクションで使用します。

CDK deploying the stacks.

CDKを使用してバックエンドAPIを構築したので、フロントエンドを接続できます。

Flutterアプリを構築してGraphQL APIに接続

このセクションでは、FlutterモバイルアプリをCDKで作成したGraphQL APIに接続します。まず、Flutterプロジェクトを初期化し、スキーマに一致するモデルを定義し、AmplifyでCRUD操作を統合します。その後、ToDoアイテムを管理するためのUIページを追加して、クエリとミューテーションを追加します。最後に、バックエンド詳細でAmplifyを構成し、アプリを実行して、既存のAPIとの完全な機能を実演します。

ステップ1: ターミナルで次のコマンドを実行してFlutterアプリを作成します。

Terminal
flutter create flutter_todo_app --platforms=web

ステップ2: ターミナルで次のコマンドを実行して、新しく作成されたFlutterアプリを開きます。

Terminal
cd flutter_todo_app
code . -r

ステップ3: 次のコードに示すように、アプリのルートディレクトリのpubspec.yamlファイルを更新して、必要な依存関係を追加します。

pubspec.yaml
name: flutter_todo_app
description: "A new Flutter project."
publish_to: 'none' # Remove this line if you wish to publish to pub.dev
version: 1.0.0+1
dependencies:
flutter:
sdk: flutter
amplify_flutter: ^2.0.0
amplify_api: ^2.0.0
go_router: ^6.5.5
cupertino_icons: ^1.0.2
dev_dependencies:
flutter_test:
sdk: flutter
flutter_lints: ^2.0.0
flutter:
uses-material-design: true

ステップ4: ターミナルで次のコマンドを実行して、pubspec.yamlファイルに追加した依存関係をインストールします。

Terminal
flutter pub get

ステップ5: 次のコマンドを実行して、@aws-amplify/cliパッケージをインストールします。

Terminal
npm install @aws-amplify/cli

ステップ6: graphqlという名前の新しいフォルダを作成し、その中にファイルschema.graphqlを作成します。

The schema.graphql file inside the graphql folder.

ステップ7: 次の例に示すようにschema.graphqlファイルを更新して、CDKアプリで使用したものと同様のToDoデータモデルを定義します。

schema.graphql
type Todo @model @auth(rules: [{ allow: public }]) {
id: ID!
name: String!
description: String
complete: Boolean
}

ステップ8: 次のコマンドを実行して、lib/modelsフォルダ内にGraphQLクライアントヘルパーモデルを生成します。

npx @aws-amplify/cli codegen models --model-schema ./graphql --target flutter --output-dir ./lib/models
The ModelProvider.dart and Todo.dart files within the models folder.

ステップ9: libフォルダ内にtodo_item_page.dartファイルを作成し、次のコードで更新して、ユーザーがToDoアイテムを作成するためのフォームを提示します。送信されると、フォームはGraphQLミューテーションを開始して、データベース内のアイテムを追加または変更します。

todo_item_page.dart
import 'package:amplify_api/amplify_api.dart';
import 'package:amplify_flutter/amplify_flutter.dart';
import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';
import '../models/ModelProvider.dart';
class ToDoItemPage extends StatefulWidget {
const ToDoItemPage({
required this.todoItem,
super.key,
});
final Todo? todoItem;
State<ToDoItemPage> createState() => _ToDoItemPageState();
}
class _ToDoItemPageState extends State<ToDoItemPage> {
final _formKey = GlobalKey<FormState>();
final TextEditingController _nameController = TextEditingController();
final TextEditingController _descriptionController = TextEditingController();
late final String _nameText;
late bool _isDone;
bool get _isCreate => _todoItem == null;
Todo? get _todoItem => widget.todoItem;
void initState() {
super.initState();
final todoItem = _todoItem;
if (todoItem != null) {
_nameController.text = todoItem.name;
_descriptionController.text = todoItem.description ?? '';
_nameText = 'Update to-do Item';
_isDone = todoItem.complete ?? false;
} else {
_nameText = 'Create to-do Item';
_isDone = false;
}
}
void dispose() {
_nameController.dispose();
_descriptionController.dispose();
super.dispose();
}
Future<void> submitForm() async {
if (!_formKey.currentState!.validate()) {
return;
}
// If the form is valid, submit the data
final name = _nameController.text;
final description = _descriptionController.text;
final complete = _isDone;
if (_isCreate) {
// Create a new todo item
final newEntry = Todo(
name: name,
description: description.isNotEmpty ? description : null,
complete: complete,
);
final request = ModelMutations.create(newEntry);
final response = await Amplify.API.mutate(request: request).response;
safePrint('Create result: $response');
} else {
// Update todoItem instead
final updateToDoItem = _todoItem!.copyWith(
name: name,
description: description.isNotEmpty ? description : null,
complete: complete,
);
final request = ModelMutations.update(updateToDoItem);
final response = await Amplify.API.mutate(request: request).response;
safePrint('Update result: $response');
}
// Navigate back to homepage after create/update executes
if (mounted) {
context.pop();
}
}
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(_nameText),
),
body: Align(
alignment: Alignment.topCenter,
child: ConstrainedBox(
constraints: const BoxConstraints(maxWidth: 800),
child: Padding(
padding: const EdgeInsets.all(16),
child: SingleChildScrollView(
child: Form(
key: _formKey,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
TextFormField(
controller: _nameController,
decoration: const InputDecoration(
labelText: 'Name (required)',
),
validator: (value) {
if (value == null || value.isEmpty) {
return 'Please enter a name';
}
return null;
},
),
TextFormField(
controller: _descriptionController,
decoration: const InputDecoration(
labelText: 'Description',
),
),
SwitchListTile(
title: const Text('Done'),
value: _isDone,
onChanged: (bool value) {
setState(() {
_isDone = value;
});
},
secondary: const Icon(Icons.done_all_outlined),
),
const SizedBox(height: 20),
ElevatedButton(
onPressed: submitForm,
child: Text(_nameText),
),
],
),
),
),
),
),
),
);
}
}

ステップ10: libフォルダ内にhome_page.dart.dartファイルを作成し、次のコードで更新します。このページはGraphQLクエリを使用してToDoアイテムのリストを取得し、ListViewウィジェットで表示します。このページでは、GraphQLミューテーションを使用してToDoアイテムを削除することもできます。

home_page.dart.dart
import 'package:amplify_api/amplify_api.dart';
import 'package:amplify_flutter/amplify_flutter.dart';
import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';
import '../models/ModelProvider.dart';
class HomePage extends StatefulWidget {
const HomePage({super.key});
State<HomePage> createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
var _todoItems = <Todo>[];
void initState() {
super.initState();
_refreshTodoItems();
}
Future<void> _refreshTodoItems() async {
try {
final request = ModelQueries.list(Todo.classType);
final response = await Amplify.API.query(request: request).response;
final todos = response.data?.items;
if (response.hasErrors) {
safePrint('errors: ${response.errors}');
return;
}
setState(() {
_todoItems = todos!.whereType<Todo>().toList();
});
} on ApiException catch (e) {
safePrint('Query failed: $e');
}
}
Future<void> _deleteToDoItem(Todo todoItem) async {
final request = ModelMutations.delete<Todo>(todoItem);
final response = await Amplify.API.mutate(request: request).response;
safePrint('Delete response: $response');
await _refreshTodoItems();
}
Future<void> _openToDoItem({Todo? todoItem}) async {
await context.pushNamed('manage', extra: todoItem);
// Refresh the entries when returning from the
// todo item screen.
await _refreshTodoItems();
}
Widget _buildRow({
required String name,
required String description,
required bool isDone,
TextStyle? style,
}) {
return Row(
children: [
Expanded(
child: Text(
name,
textAlign: TextAlign.center,
style: style,
),
),
Expanded(
child: Text(
description,
textAlign: TextAlign.center,
style: style,
),
),
Expanded(
child: isDone ? const Icon(Icons.done) : const SizedBox(),
),
],
);
}
Widget build(BuildContext context) {
return Scaffold(
floatingActionButton: FloatingActionButton(
// Navigate to the page to create new todo item
onPressed: _openToDoItem,
child: const Icon(Icons.add),
),
appBar: AppBar(
title: const Text('To-Do List'),
),
body: Center(
child: Padding(
padding: const EdgeInsets.only(top: 25),
child: RefreshIndicator(
onRefresh: _refreshTodoItems,
child: Column(
children: [
if (_todoItems.isEmpty)
const Text('Use the \u002b sign to add new to-do items')
else
const SizedBox(height: 30),
_buildRow(
name: 'Name',
description: 'Description',
isDone: false,
style: Theme.of(context).textTheme.titleMedium,
),
const Divider(),
Expanded(
child: ListView.builder(
itemCount: _todoItems.length,
itemBuilder: (context, index) {
final todoItem = _todoItems[index];
return Dismissible(
key: ValueKey(todoItem),
background: const ColoredBox(
color: Colors.red,
child: Padding(
padding: EdgeInsets.only(right: 10),
child: Align(
alignment: Alignment.centerRight,
child: Icon(Icons.delete, color: Colors.white),
),
),
),
onDismissed: (_) => _deleteToDoItem(todoItem),
child: ListTile(
onTap: () => _openToDoItem(
todoItem: todoItem,
),
title: _buildRow(
name: todoItem.name,
description: todoItem.description ?? '',
isDone: todoItem.complete ?? false,
),
),
);
},
),
),
],
),
),
),
),
);
}
}

ステップ11: main.dartを更新して、前のセクションでCDKアプリを使用して作成したGraphQL APIの詳細を使用してAmplifyを構成します。

main.dart
import 'package:amplify_api/amplify_api.dart';
import 'package:amplify_flutter/amplify_flutter.dart';
import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';
import 'models/ModelProvider.dart';
import 'home_page.dart';
import 'todo_item_page.dart';
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
await _configureAmplify();
runApp(const MyApp());
}
Future<void> _configureAmplify() async {
try {
final api = AmplifyAPI(modelProvider: ModelProvider.instance);
await Amplify.addPlugins([api]);
const amplifyconfig = '''{
"api": {
"plugins": {
"awsAPIPlugin": {
"flutter_todo_app": {
"endpointType": "GraphQL",
"endpoint": "<The-GraphQL-Endpoint>",
"region": "<The-Region>",
"authorizationType": "API_KEY",
"apiKey": "<The-API-KEY-Value>"
}
}
}
}
}''';
await Amplify.configure(amplifyconfig);
safePrint('Successfully configured');
} on Exception catch (e) {
safePrint('Error configuring Amplify: $e');
}
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
// GoRouter configuration
static final _router = GoRouter(
routes: [
GoRoute(
path: '/',
builder: (context, state) => const HomePage(),
),
GoRoute(
path: '/manage-todo-item',
name: 'manage',
builder: (context, state) => ToDoItemPage(
todoItem: state.extra as Todo?,
),
),
],
);
Widget build(BuildContext context) {
return MaterialApp.router(
routerConfig: _router,
debugShowCheckedModeBanner: false,
builder: (context, child) {
return child!;
},
);
}
}

ステップ12: 次のコマンドを使用してChromブラウザでアプリを実行します。

Terminal
flutter run -d chrome

結論

おめでとうございます!AWS Amplify Data CDKコンストラクトを使用してGraphQL APIバックエンドをAWS AppSyncで作成しました。次に、Amplifyライブラリを使用してアプリをそのAPIに接続しました。フィードバックがある場合は、GitHubの問題を残すか、Discordコミュニティに参加してください!

リソースのクリーンアップ

このデモアプリの実験が終了したら、予期しない費用が発生しないようにバックエンドリソースを削除することをお勧めします。これは、上記で作成したCDKアプリのルートフォルダで次のコマンドを実行することで実行できます。

Terminal
cdk destroy