---
title: GraphQL을 활용한 Flutter CRUD 앱 템플릿 구현 가이드
slug: docs-kr/flutter/graphql/flutter-crud-app-example
description: Flutter와 GraphQL을 활용해 CRUD 기능의 앱을 구축하는 방법을 알아봅니다. 데이터 생성, 업데이트, 삭제를 단계적으로 구현합니다.
image: https://www.back4app.com/images/logo-social.png
createdAt: 2024-03-18T18:51:24.936Z
---

# GraphQL을 사용한 Flutter CRUD 앱 예제



## 소개

첫 번째 Flutter-GraphQL 가이드에서는 GraphQL API를 사용하여 Back4App에서 간단한 데이터에 연결하고 쿼리하는 Flutter 프로젝트를 설정하는 방법을 배웠습니다. 또한, Back4App GraphQL Playground를 사용하여 쿼리/변경 작업을 실행하여 앱 데이터베이스를 생성/채우는 방법도 배웠습니다.

이 튜토리얼에서는 GraphQL 변형을 사용하여 앱에서 Back4App 백엔드에서 직접 데이터를 생성, 업데이트 및 삭제하는 기능을 추가할 것입니다.

## 목표

이 기사의 끝에서 여러분이 할 수 있기를 기대하는 것은:

- GraphQL API를 사용하여 백엔드에 데이터를 생성합니다.
- GraphQL API를 사용하여 백엔드에서 데이터를 업데이트합니다.
- GraphQL API를 사용하여 백엔드에서 기존 데이터를 삭제합니다.

::Image[]{src="https://api.archbee.com/api/optimize/yD3zCY-NNBBIfd0uqcfR5/kPiedmPCadGXn4Vz8Kz3Q_flutter-createdata.gif" size="50" width="270" height="480" position="center" showCaption="false"}

## 전제 조건

:::hint{type="info"}
**이 튜토리얼을 완료하려면 다음이 필요합니다:**

- 이 가이드를 이해하기 위해 이전 가이드를 읽어야 합니다 [“Flutter GraphQL 프로젝트”](https://www.back4app.com/docs/flutter/graphql/flutter-graphql-project-with-source-code-download).
- 이전 프로젝트를 사용할 예정입니다. 없다면 [여기에서 다운로드하세요](https://github.com/templates-back4app/Flutter-GraphQL).
- Android Studio 또는 VS Code와 같은 Flutter 코드를 작성할 수 있는 IDE.
- 다음에서 [계정을 생성할 수 있는 Back4App](https://www.back4app.com/).
- [Back4App GraphQL\_flutter 의존성](https://pub.dev/packages/graphql_flutter)
:::

:::hint{type="success"}
참고: Back4App GraphQL API에 대한 더 나은 이해를 원하신다면 [GraphQL 요리책](https://www.back4app.com/docs/parse-graphql/graphql-getting-started)을 확인하고 API 플레이그라운드에서 GraphQL 스키마도 확인하세요.
:::

## 1 - GUI 설정하기

새 파일을 생성하세요 <font color="#2166ae">`mutation_page.dart`</font>. 여기서 우리는 사용자로부터 입력을 받고 변이 작업을 수행하기 위한 GUI를 생성할 것입니다. 이제 다음 코드를 <font color="#2166ae">`mutation_page.dart`</font>에 붙여넣으세요.

```dart
1   import 'package:back4appgraphqldemo/app_ui.dart';
2   import 'package:back4appgraphqldemo/database_utils.dart';
3   import 'package:flutter/material.dart';
4
5   class MutationPage extends StatelessWidget {
6
7     String langName,saveFormat,objectId;
8     DatabaseUtils utils;
9
10    @override
11    Widget build(BuildContext context) {
12      return AppUI(
13        onChangedName: (text){
14        langName=text;
15        },
16        onChangedSaveFormat: (text){
17                saveFormat=text;
18          },
19        onChangedObjectId: (text){
20        objectId=text;
21        },
22        sendDataButtonPressed: (){
23        },
24        deleteDataButtonPressed: (){
25        },
26        updateButtonPressed: (){
27        },
28      );
29    }
30  }
```

<font color="#2166ae">`AppUI()`</font> 위젯은 이미 만들어졌습니다. 그래서 우리는 <font color="#2166ae">`MutationPage`</font>라는 이름의 클래스를 생성하고 <font color="#2166ae">`AppUI`</font> 위젯을 반환했습니다. 또한 텍스트 필드에 대한 콜백 함수를 초기화하여 첫 번째 텍스트 필드의 텍스트는 <font color="#2166ae">`langName`</font>, 두 번째는 <font color="#2166ae">`saveFormat`</font>에 저장되고 마지막으로 <font color="#2166ae">`objectId`</font>에 저장됩니다. 이제 <font color="#2166ae">`main.dart`</font>로 진행하여 <font color="#2166ae">`floatingActionButton`</font> 매개변수를 <font color="#2166ae">`Scaffold()`</font> 위젯의 <font color="#2166ae">`MyHomePage`</font> 클래스에 추가하고 다음 코드를 전달하세요:

```dart
1   floatingActionButton: Row(
2             mainAxisAlignment: MainAxisAlignment.end,
3             children: [
4               FloatingActionButton(
5                 heroTag: 'mutation_page',
6                 child: Text('M',
7                 style: TextStyle(
8                   color: Colors.white,
9                 ),
10                ),
11                onPressed: (){
12                  Navigator.pushReplacement(context, MaterialPageRoute(
13                    builder: ((context){
14                      return MutationPage();
15                    })
16                  ));
17                },
18              ),
19            ],
20          ),
```

이것은 우리가 홈 페이지에서 <font color="#2166ae">`MutationPage()`</font>로 이동할 Floating Button을 생성합니다. 이제 우리의 GUI가 설정되었습니다. 이제 앱을 Hot Restart하여 GUI를 확인할 수 있습니다. 당신의 <font color="#2166ae">`main.dart`</font>는 다음과 같아야 합니다:

```dart
1   import 'package:back4appgraphqldemo/mutation_page.dart';
2   import 'package:flutter/material.dart';
3   import 'package:graphql_flutter/graphql_flutter.dart';
4   import 'consonents.dart';
5   import 'dart:ui';
6
7   void main() {
8     runApp(MyApp());
9   }
10
11  class MyApp extends StatelessWidget {
12    @override
13    Widget build(BuildContext context) {
14      final HttpLink httpLink = HttpLink(
15        uri: 'https://parseapi.back4app.com/graphql',
16        headers: {
17          'X-Parse-Application-Id': kParseApplicationId,
18          'X-Parse-Client-Key': kParseClientKey,
19          'X-Parse-Master-Key': kParseMasterKey,
20          //'X-Parse-REST-API-Key' : kParseRestApiKey,
21        }, //getheaders()
22      );
23
24      ValueNotifier<GraphQLClient> client = ValueNotifier(
25        GraphQLClient(
26          cache: OptimisticCache(dataIdFromObject: typenameDataIdFromObject),
27          link: httpLink,
28        ),
29      );
30  
31      return MaterialApp(
32        home: GraphQLProvider(
33          child: MyHomePage(),
34          client: client,
35        ),
36      );
37    }
38  }
39
40  class MyHomePage extends StatefulWidget {
41    @override
42    _MyHomePageState createState() => _MyHomePageState();
43  }
44
45  class _MyHomePageState extends State<MyHomePage> {
46    String name;
47    String saveFormat;
48    String objectId;
49  
50    String query = '''
51    query FindLanguages{
52    languages{
53      count,
54      edges{
55        node{
56          name,
57          saveFormat
58        }
59      }
60    }
61  }
62    ''';
63  
64    @override
65    Widget build(BuildContext context) {
66      return SafeArea(
67        child: Scaffold(
68          appBar: AppBar(
69            title: Text(
70              'Parsing data using GraphQL',
71            ),
72          ),
73          floatingActionButton: Row(
74            mainAxisAlignment: MainAxisAlignment.end,
75            children: [
76              FloatingActionButton(
77                heroTag: 'mutation_page',
78                child: Text('M',
79                style: TextStyle(
80                  color: Colors.white,
81                ),
82                ),
83                onPressed: (){
84                  Navigator.pushReplacement(context, MaterialPageRoute(
85                    builder: ((context){
86                      return MutationPage();
87                    })
88                  ));
89                },
90              ),
91            ],
92          ),
93          body: Query(
94            options: QueryOptions(
95              documentNode: gql(query),
96            ),
97            builder: (
98              QueryResult result, {
99              Refetch refetch,
100             FetchMore fetchMore,
101           }) {
102             if (result.data == null) {
103               return Center(
104                   child: Text(
105                 "Loading...",
106                 style: TextStyle(fontSize: 20.0),
107               ));
108             } else {
109               return ListView.builder(
110                 itemBuilder: (BuildContext context, int index) {
111                   return ListTile(
112                     title: Text(result.data["languages"]["edges"][index]["node"]
113                         ['name']),
114                     trailing: Text(result.data["languages"]["edges"][index]
115                         ["node"]['saveFormat']),
116 
117                   );
118                 },
119                 itemCount: result.data["languages"]["edges"].length,
120               );
121             }
122           },
123         ),
124       ),
125     );
126   }
127 }
```

## 2 - 데이터베이스에 데이터 생성/추가하기

진행하면 <font color="#2166ae">`graphql_configration.dart`</font>를 볼 수 있으며, 이미 <font color="#2166ae">`GraphQLclient`</font>을 설정했습니다. 이제 어디서나 사용할 수 있습니다. 다음으로 <font color="#2166ae">`database_utils.dart`</font> 파일을 생성하고 **데이터 생성** 작업을 수행합니다. <font color="#2166ae">`DatabaseUtils{}`</font> 클래스를 생성하고 우리가 작업할 데이터 매개변수를 받을 생성자를 만듭니다. 여기서는 <font color="#2166ae">`langName`</font>,<font color="#2166ae">`saveFormat`</font>, 그리고 <font color="#2166ae">`objectId`</font>:

```dart
1   import 'package:back4appgraphqldemo/graphql_configration.dart';
2   import 'package:graphql_flutter/graphql_flutter.dart';
3
4   class DatabaseUtils{
5     final String langName,saveFormat,objectId;
6     DatabaseUtils({this.langName="",this.saveFormat="",this.objectId=""});
7   }
```

함수 <font color="#2166ae">`addData()`</font>를 생성합니다. 이 함수는 데이터를 생성하고 <font color="#2166ae">`GraphQLClient`</font>를 초기화하는 비동기 함수가 될 것입니다. <font color="#2166ae">`GraphQLConfigration`</font> 클래스를 초기화합니다. 다음 코드를 <font color="#2166ae">`sendData()`</font> 함수에 붙여넣습니다:

```dart
1    Future<QueryResult> sendData() async{
2        String addData='''
3         mutation CreateObject(\$input: CreateLanguageFieldsInput){
4           createLanguage(input: {fields: \$input}){
5             language{
6               name,
7               saveFormat
8             }
9           }
10        }
11         ''';
12        final variable ={
13       "input":{
14         "name" : langName,
15         "saveFormat" : saveFormat,
16       }
17     };
18        
19      GraphQlConfiguration configuration = GraphQlConfiguration();
20     GraphQLClient client = configuration.clientToQuery();
21   
22     }
```

여기에서 우리는 <font color="#2166ae">`addData`</font> 변수를 초기화하고 데이터를 생성하기 위한 쿼리를 전달했으며 <font color="#2166ae">`변수`</font>를 전달할 쿼리 변수를 초기화했습니다. 또한 쿼리를 전달하는 데 도움이 되는 <font color="#2166ae">`GraphQLClient`</font>를 초기화했습니다. 아래와 같은 방식으로 쿼리를 전달할 수 있습니다:

```dart
1   QueryResult queryResult = await client.query(
2        QueryOptions(documentNode: gql(addData), variables: variable),
3      );
4      return queryResult;
```

우리는 <font color="#2166ae">`GraphQLClient`</font> 인스턴스를 사용하여 <font color="#2166ae">`QueryOptions()`</font>를 수용하는 쿼리를 작성했습니다. 이는 지난 튜토리얼에서 보았던 것처럼 쿼리를 전송하는 데 도움이 됩니다. 결과는 <font color="#2166ae">`queryResult`</font>.
당신의 <font color="#2166ae">`database_utils.dart`</font>는 다음과 같아야 합니다:

```dart
1   import 'package:back4appgraphqldemo/graphql_configration.dart';
2   import 'package:graphql_flutter/graphql_flutter.dart';
3
4   class DatabaseUtils{
5     final String langName,saveFormat,objectId;
6     DatabaseUtils({this.langName="",this.saveFormat="",this.objectId=""});
7     Future<QueryResult> sendData() async{
8       String addData='''
9         mutation CreateObject(\$input: CreateLanguageFieldsInput){
10          createLanguage(input: {fields: \$input}){
11            language{
12              name,
13              saveFormat
14            }
15          }
16        }
17        ''';
18      final variable ={
19        "input":{
20          "name" : langName,
21          "saveFormat" : saveFormat,
22         }
23      };
24 
25      GraphQlConfiguration configuration = GraphQlConfiguration();
26      GraphQLClient client = configuration.clientToQuery();
27
28      QueryResult queryResult = await client.query(
29        QueryOptions(documentNode: gql(addData), variables: variable),
30      );
31      return queryResult;
32    }
33  }
```

이제 UI 클래스 <font color="#2166ae">`mutation_page.dart`</font>. 데이터를 전송하는 버튼을 코딩합시다. 이는 <font color="#2166ae">`sendDataButtonPressed:`</font> 매개변수 안에 코딩할 수 있습니다. langName과 saveFormat이 필요하므로 먼저 비어 있지 않은지 확인한 후 <font color="#2166ae">`DatabaseUtils`</font>의 인스턴스를 생성하고 <font color="#2166ae">`langName`</font>과 <font color="#2166ae">`saveFormat`</font> 매개변수를 전달합니다.

```dart
1   if(langName.isNotEmpty && saveFormat.isNotEmpty){
2             utils = DatabaseUtils(
3               langName: langName,
4               saveFormat: saveFormat ,
5             );
6           }
```

이후 <font color="#2166ae">`sendData()`</font> 함수를 <font color="#2166ae">`DatabaseUtils`</font> 인스턴스에서 호출합니다.

:::BlockQuote
util&#x73;**.**&#x73;endData();
:::

이제 당신은 **Hot Restart** 앱을 실행하고 두 개의 텍스트 필드에 각각의 데이터를 입력한 후 데이터 전송 버튼을 누를 수 있습니다. 이제 플로팅 액션 버튼을 눌러 쿼리 페이지로 돌아가면 테이블에 하나의 데이터가 더 추가된 것을 볼 수 있습니다. 이것이 당신의 MutationPage 클래스의 모습입니다:

```dart
1   import 'package:back4appgraphqldemo/app_ui.dart';
2   import 'package:back4appgraphqldemo/database_utils.dart';
3   import 'package:flutter/material.dart';
4
5   class MutationPage extends StatelessWidget {
6 
7     String langName,saveFormat,objectId;
8     DatabaseUtils utils;
9
10    @override
11    Widget build(BuildContext context) {
12      return AppUI(
13        onChangedName: (text){
14        langName=text;
15        },
16        onChangedSaveFormat: (text){
17                saveFormat=text;
18          },
19        onChangedObjectId: (text){
20        objectId=text;
21        },
22        sendDataButtonPressed: (){
23        if(langName.isNotEmpty && saveFormat.isNotEmpty){
24            utils = DatabaseUtils(
25              langName: langName,
26              saveFormat: saveFormat ,
27            );
28            utils.sendData();
29          }
30        },
31        deleteDataButtonPressed: (){
32        },
33        updateButtonPressed: (){
34        },
35      );
36    }
37  }
```

::Image[]{src="https://api.archbee.com/api/optimize/yD3zCY-NNBBIfd0uqcfR5/MR8HfB7BOEW99Nko0Jpwz_flutter-createdata-1.gif" size="50" width="270" height="480" position="center" showCaption="false"}

## 3 - 데이터 업데이트

에서 <font color="#2166ae">`DatabaseUtils`</font> 함수를 생성합니다 <font color="#2166ae">`Future`</font> <font color="#2166ae">`updateData()`</font>. <font color="#2166ae">`String update`</font>를 초기화하고 업데이트 쿼리와 *쿼리 변수*를 <font color="#2166ae">`final variables`</font>:

```dart
1    Future<QueryResult> updateData() async{
2     String update='''
3     mutation UpdateObject(\$id: ID!,\$input: UpdateLanguageFieldsInput){
4       updateLanguage(input: {id:\$id, fields:\$input}){
5         language{
6           name,
7           id
8         }
9       }
10    }
11    ''';
12     final variable={
13       "id":objectId,
14       "input":{
15         "name" : langName
16       }
17     };
18   }
```

이제 우리의 <font color="#2166ae">`GraphQLClient`</font>를 초기화하고 쿼리를 <font color="#2166ae">`QueryOptions()`</font>를 통해 전송합니다. 이렇게 하면 코드가 다음과 같이 보입니다:

```dart
1   Future<QueryResult> updateData() async{
2 
3      String update='''
4       mutation UpdateObject(\$id: ID!,\$input: UpdateLanguageFieldsInput){
5         updateLanguage(input: {id:\$id, fields:\$input}){
6          language{
7             name,
8             id
9           }
10        }
11      }
12      ''';
13   
14     final variable={
15       "id":objectId,
16       "input":{
17         "name" : langName
18       }
19     };
20  
21     GraphQlConfiguration configuration = GraphQlConfiguration();
22     GraphQLClient client = configuration.clientToQuery();
23  
24     QueryResult queryResult = await client.query(
25       QueryOptions(documentNode: gql(update), variables: variable),
26    );
27     return queryResult;
28   }
```

이제 <font color="#2166ae">`mutaion_page.dart`</font>로 돌아가서 <font color="#2166ae">`updateButtonPressed:`</font> 매개변수에 코드를 작성하세요. <font color="#2166ae">`langName`</font>, <font color="#2166ae">`objectId`</font> 및 <font color="#2166ae">`saveFormat`</font>이 비어 있지 않은지 확인한 후 <font color="#2166ae">`updateData()` </font> 함수를 <font color="#2166ae">`DatabaseUtils`</font> 클래스에서 호출하세요.

```dart
1    updateButtonPressed: (){
2           if(langName.isNotEmpty && saveFormat.isNotEmpty && objectId.isNotEmpty){
3             utils = DatabaseUtils(
4               langName: langName,
5               saveFormat: saveFormat ,
6               objectId: objectId
7             );
8             utils.updateData();
9           }
10        },
```

Back4App 대시보드로 가서 업데이트할 언어를 선택한 다음 해당 objectID를 복사하세요. **핫 리스타트**를 통해 앱을 다시 시작하고 3개의 텍스트 필드를 모두 채우세요: 첫 번째 텍스트 필드에 삽입할 언어의 새로운 **이름**과 두 번째 필드에 새로운 **저장 형식** 및 세 번째 필드에 **objectId**를 입력하세요. 이제 데이터 업데이트 버튼을 눌러 앱에서 업데이트된 정보를 확인하세요. 오른쪽 하단의 Q 플로팅 액션 버튼을 클릭하세요.

::Image[]{src="https://api.archbee.com/api/optimize/yD3zCY-NNBBIfd0uqcfR5/Dhk13aMGmSxLvzbop-BuN_flutter-updatedata.gif" size="50" width="237" height="432" position="center" showCaption="false"}

## 4 - 데이터 삭제

다음과 같이 <font color="#2166ae">`deleteData()`</font> **비동기** 함수를 <font color="#2166ae">`DatabaseUtils`</font>에서 생성하고 <font color="#2166ae">`String delete`</font>를 초기화한 후, 데이터를 삭제하기 위한 GraphQL 쿼리를 전달합니다. <font color="#2166ae">`최종 변수`</font>를 가져와 쿼리 변수를 전달합니다.

```dart
1   Future<QueryResult> deleteData() async{
2       String delete='''
3     mutation DeleteObject(\$id: ID!){
4       deleteLanguage(input: {id:\$id}){
5         language{
6           name,
7           id
8         }
9       }
10    }
11    ''';
12     final variable={
13       "id":objectId,
14     };
15   }
```

여기서 우리는 삭제해야 할 행의 <font color="#2166ae">`objectId`</font>만 필요합니다. <font color="#2166ae">`GraphQLClient`</font>를 초기화하고 <font color="#2166ae">`QueryOptions()`</font>를 통해 쿼리를 전송합니다.

```dart
1   Future<QueryResult> deleteData() async{
2        String delete='''
3     mutation DeleteObject(\$id: ID!){
4       deleteLanguage(input: {id:\$id}){
5         language{
6           name,
7           id
8         }
9       }
10    }
11    ''';
12     final variable={
13       "id":objectId,
14     };
15
16     GraphQlConfiguration configuration = GraphQlConfiguration();
17     GraphQLClient client = configuration.clientToQuery();
18  
19     QueryResult queryResult = await client.query(
20       QueryOptions(documentNode: gql(delete), variables: variable),
21     );
22
23     return queryResult;
24   }
```

에서 <font color="#2166ae">`MutationPage`</font> 의 <font color="#2166ae">`deleteDataButtonPressed`</font>: 매개변수는 <font color="#2166ae">`objectId`</font>가 비어 있거나 null이 아닌지 확인하고 <font color="#2166ae">`deleteData()`</font> 함수를 호출합니다. **핫 리스타트** 애플리케이션에서 삭제할 행의 **objectId**를 입력하고 **데이터 삭제** 버튼을 누릅니다. 특정 행이 <font color="#2166ae">`Language`</font> 클래스에서 삭제되어야 합니다.

::Image[]{src="https://api.archbee.com/api/optimize/yD3zCY-NNBBIfd0uqcfR5/cFrVVPxzehrwhzb9yosaD_flutter-deletedata.gif" size="50" width="270" height="480" position="center" showCaption="false"}

***성공***&#xC801;으로 앱이 마침내 변환 작업을 완료했습니다 !!!

<font color="#2166ae">`main.dart`</font> 는 다음과 같아야 합니다:

```dart
1   import 'package:back4appgraphqldemo/mutation_page.dart';
2   import 'package:flutter/material.dart';
3   import 'package:graphql_flutter/graphql_flutter.dart';
4   import 'consonents.dart';
5   import 'dart:ui';
6
7   void main() {
8     runApp(MyApp());
9   }
10
11  class MyApp extends StatelessWidget {
12    @override
13    Widget build(BuildContext context) {
14      final HttpLink httpLink = HttpLink(
15        uri: 'https://parseapi.back4app.com/graphql',
16        headers: {
17          'X-Parse-Application-Id': kParseApplicationId,
18          'X-Parse-Client-Key': kParseClientKey,
19          'X-Parse-Master-Key': kParseMasterKey,
20          //'X-Parse-REST-API-Key' : kParseRestApiKey,
21        }, //getheaders()
22      );
23  
24      ValueNotifier<GraphQLClient> client = ValueNotifier(
25        GraphQLClient(
26          cache: OptimisticCache(dataIdFromObject: typenameDataIdFromObject),
27          link: httpLink,
28        ),
29      );
30  
31      return MaterialApp(
32        home: GraphQLProvider(
33          child: MyHomePage(),
34          client: client,
35        ),
36      );
37   }
38  }
39  
40  class MyHomePage extends StatefulWidget {
41    @override
42    _MyHomePageState createState() => _MyHomePageState();
43  }
44 
45  class _MyHomePageState extends State<MyHomePage> {
46    String name;
47    String saveFormat;
48    String objectId;
49
50    String query = '''
51    query FindLanguages{
52    languages{
53      count,
54      edges{
55        node{
56          name,
57          saveFormat
58        }
59      }
60    }
61  }
62    ''';
63  
64    @override
65    Widget build(BuildContext context) {
66      return SafeArea(
67        child: Scaffold(
68          appBar: AppBar(
69            title: Text(
70              'Parsing data using GraphQL',
71            ),
72          ),
73          floatingActionButton: Row(
74            mainAxisAlignment: MainAxisAlignment.end,
75            children: [
76              FloatingActionButton(
77                heroTag: 'mutation_page',
78                child: Text('M',
79                style: TextStyle(
80                  color: Colors.white,
81                ),
82                ),
83                onPressed: (){
84                  Navigator.pushReplacement(context, MaterialPageRoute(
85                    builder: ((context){
86                      return MutationPage();
87                    })
88                  ));
89                },
90              ),
91            ],
92          ),
93          body: Query(
94            options: QueryOptions(
95              documentNode: gql(query),
96            ),
97            builder: (
98              QueryResult result, {
99              Refetch refetch,
100             FetchMore fetchMore,
101           }) {
102             if (result.data == null) {
103               return Center(
104                   child: Text(
105                 "Loading...",
106                 style: TextStyle(fontSize: 20.0),
107               ));
108             } else {
109               return ListView.builder(
110                 itemBuilder: (BuildContext context, int index) {
111                   return ListTile(
112                     title: Text(result.data["languages"]["edges"][index]["node"]
113                         ['name']),
114                     trailing: Text(result.data["languages"]["edges"][index]
115                         ["node"]['saveFormat']),
116 
117                   );
118                 },
119                 itemCount: result.data["languages"]["edges"].length,
120              );
121             }
122           },
123         ),
124       ),
125     );
126   }
127 }
```

<font color="#2166ae">`database_utils.dart`</font> 는 다음과 같아야 합니다:

```dart
1   import 'package:back4appgraphqldemo/graphql_configration.dart';
2   import 'package:graphql_flutter/graphql_flutter.dart';
3
4   class DatabaseUtils{
5
6     final String langName,saveFormat,objectId;
7
8     DatabaseUtils({this.langName="",this.saveFormat="",this.objectId=""});
9
10    String delete='''
11    mutation DELETE_LANGUAGES(\$id: ID!){
12      deleteLanguage(input: {id:\$id}){
13        language{
14          name,
15          id
16        }
17      }
18    }
19    ''';
20  
21    String addData='''
22    mutation CREATE_LANGUAGES(\$input: CreateLanguageFieldsInput){
23      createLanguage(input: {fields: \$input}){
24        language{
25          name,
26          saveFormat
27        }
28      }
29    }
30    ''';
31    String update='''
32    mutation UPDATE_LANGUAGES(\$id: ID!,\$input: UpdateLanguageFieldsInput){
33      updateLanguage(input: {id:\$id, fields:\$input}){
34        language{
35          name,
36          id
37        }
38      }
39    }
40    ''';
41
42   Future<QueryResult> sendData() async{
43
44     final variable ={
45       "input":{
46         "name" : langName,
47         "saveFormat" : saveFormat,
48       }
49     };
50     print('sendingData');
51  
52      GraphQlConfiguration configuration = GraphQlConfiguration();
53     GraphQLClient client = configuration.clientToQuery();
54  
55     QueryResult queryResult = await client.query(
56       QueryOptions(documentNode: gql(addData), variables: variable),
57     );
58     return queryResult;
59  
60   }
61   Future<QueryResult> updateData() async{
62     final variable={
63       "id":objectId,
64       "input":{
65         "name" : langName
66       }
67     };
68  
69     GraphQlConfiguration configuration = GraphQlConfiguration();
70     GraphQLClient client = configuration.clientToQuery();
71  
72     QueryResult queryResult = await client.query(
73       QueryOptions(documentNode: gql(update), variables: variable),
74     );
75     return queryResult;
76   }
77
78
79   Future<QueryResult> deleteData() async{
80     final variable={
81       "id":objectId,
82     };
83  
84     GraphQlConfiguration configuration = GraphQlConfiguration();
85     GraphQLClient client = configuration.clientToQuery();
86  
87     QueryResult queryResult = await client.query(
88     QueryOptions(documentNode: gql(delete), variables: variable),
89     );
90  
91     return queryResult;
92   }
93  }
```

<font color="#2166ae">`mutaion_page.dart`</font>는 다음과 같아야 합니다 :

```dart
1   import 'package:back4appgraphqldemo/app_ui.dart';
2   import 'package:back4appgraphqldemo/database_utils.dart';
3   import 'package:flutter/material.dart';
4
5   class MutationPage extends StatelessWidget {
6
7     String langName,saveFormat,objectId;
8     DatabaseUtils utils;
9
10    @override
11    Widget build(BuildContext context) {
12      return AppUI(
13        onChangedName: (text){
14          langName=text;
15        },
16        onChangedSaveFormat: (text){
17          saveFormat=text;
18          },
19        onChangedObjectId: (text){
20          objectId=text;
21        },
22
23        sendDataButtonPressed: (){
24          if(langName.isNotEmpty && saveFormat.isNotEmpty){
25            utils = DatabaseUtils(
26              langName: langName,
27              saveFormat: saveFormat ,
28            );
29            utils.sendData();
30          }
31        },
32        deleteDataButtonPressed: (){
33          if(objectId.isNotEmpty){
34            utils = DatabaseUtils(
35              objectId: objectId,
36            );
37            utils.deleteData();
38          }
39        },
40        updateButtonPressed: (){
41          if(langName.isNotEmpty && saveFormat.isNotEmpty && objectId.isNotEmpty){
42            utils = DatabaseUtils(
43              langName: langName,
44              saveFormat: saveFormat ,
45              objectId: objectId
46            );
47            utils.updateData();
48           }
49        },
50      );
51    }
52  }
```

## 결론

이 가이드에서는 Flutter 앱에서 GraphQL 변이를 사용하여:

- **Back4App에서 새 객체를 생성합니다;**
- **Back4App에서 객체를 업데이트합니다;**
- **Back4App에서 객체를 삭제합니다.**

이 시점에서 여러분은 완전한 기능을 갖춘 Flutter GraphQL CRUD 프로젝트를 가지고 있으며, 이를 시작점으로 삼아 다음 앱을 개발할 수 있습니다. 다음 가이드에서는 쿼리에 대해 깊이 파고들어 Back4App에서 데이터를 검색하고 Flutter 앱에 표시하는 방법을 보여줄 것입니다.

**좋은 하루 되세요!**
