Пример CRUD приложения на Flutter с использованием GraphQL
18 мин
пример приложения flutter crud с использованием graphql введение в нашем первом руководстве по flutter graphql мы узнали, как настроить проект flutter с использованием graphql api для подключения и запроса простых данных на back4app также мы узнали, как использовать graphql playground от back4app для выполнения запросов/мутаций для создания/заполнения базы данных приложения в этом учебном пособии мы добавим функцию, с помощью которой мы сможем напрямую создавать, обновлять и удалять данные из нашего бэкенда back4app прямо из нашего приложения, используя мутации graphql цели в конце этой статьи мы ожидаем, что вы сможете создавать данные в нашем бэкенде с использованием graphql api обновлять данные из нашего бэкенда с использованием graphql api удалять существующие данные из бэкенда с использованием graphql api предварительные условия чтобы завершить этот учебник, вам потребуется вам нужно прочитать наше предыдущее руководство “проект flutter graphql” https //www back4app com/docs/flutter/graphql/flutter graphql project with source code download для того, чтобы понять нашу отправную точку в этом руководстве мы будем использовать предыдущий проект, если у вас его нет, вы можете скачать его здесь https //github com/templates back4app/flutter graphql ide для написания кода flutter, например, android studio или vs code аккаунт back4app, который можно создать здесь https //www back4app com/ зависимость back4app graphql flutter https //pub dev/packages/graphql flutter примечание если вы хотите лучше понять api graphql back4app, ознакомьтесь с нашим кулинарной книгой graphql https //www back4app com/docs/parse graphql/graphql getting started и также проверьте нашу схему graphql на нашем api playground 1 настройка gui создайте новый файл \<font color="#2166ae">mutation page dart\</font> здесь мы создадим наш gui для ввода данных от пользователя и выполнения задач мутации теперь вставьте следующий код в \<font color="#2166ae">mutation page dart\</font> 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> и передайте в него следующий код 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> с нашей главной страницы теперь наш gui настроен вы можете перезапустить ваше приложение, чтобы увидеть gui вот как ваш \<font color="#2166ae">main dart\</font> должен выглядеть 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> 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> функцию 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> который поможет нам передавать запросы мы можем передавать запросы следующим образом 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> 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> поскольку нам нужно имя языка и формат сохранения, сначала проверьте, не пустые ли они, а затем создайте экземпляр \<font color="#2166ae">databaseutils\</font> и передайте \<font color="#2166ae">langname\</font> и \<font color="#2166ae">saveformat\</font> параметр 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> utils senddata(); теперь вы можете hot restart приложение, заполните два текстовых поля соответствующими данными и нажмите кнопку отправки данных теперь вернитесь на страницу запроса, нажав на плавающую кнопку действия, и вы увидите, что в нашу таблицу добавлены еще одни данные вот как будет выглядеть ваш класс mutationpage 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 } 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> 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> вот как будет выглядеть ваш код 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> 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 в правом нижнем углу 4 удаление данных создайте \<font color="#2166ae">deletedata()\</font> асинхронную функцию в \<font color="#2166ae">databaseutils\</font> и инициализируйте \<font color="#2166ae">string delete\</font> и передайте запрос graphql для удаления данных возьмите \<font color="#2166ae">финальные переменные\</font> и передайте переменные запроса в него 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> 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">язык\</font> класса успех ваше приложение наконец то выполнило ваши операции мутации !!! \<font color="#2166ae">main dart\</font> должен выглядеть так 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> должно выглядеть так 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> должен выглядеть так 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 } заключение в этом руководстве мы использовали мутации graphql в приложении flutter для создания новых объектов на back4app; обновления объектов на back4app; удаления объектов на back4app на данный момент у вас есть полностью функциональный проект flutter graphql crud, который вы можете использовать в качестве отправной точки для разработки вашего следующего приложения в следующем руководстве мы углубимся в запросы, показывая, как их делать для получения данных из back4app и отображения в нашем приложении flutter хорошего дня!