Flutter
GraphQL
Пример CRUD приложения на Flutter с использованием GraphQL
18 мин
пример приложения flutter crud с использованием graphql введение в нашем первом руководстве по flutter graphql мы узнали, как настроить проект flutter с использованием graphql api для подключения и запроса простых данных на back4app также мы узнали, как использовать graphql playground от back4app для выполнения запросов/мутаций для создания/заполнения базы данных приложения в этом учебном пособии мы добавим функцию, с помощью которой мы сможем напрямую создавать, обновлять и удалять данные из нашего бэкенда back4app прямо из нашего приложения, используя мутации graphql цели в конце этой статьи мы ожидаем, что вы сможете создавать данные в нашем бэкенде с использованием graphql api обновлять данные из нашего бэкенда с использованием graphql api удалять существующие данные из бэкенда с использованием graphql api предварительные условия чтобы завершить этот учебник, вам потребуется вам нужно прочитать наше предыдущее руководство 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/ https //pub dev/packages/graphql flutter примечание если вы хотите лучше понять api graphql back4app, ознакомьтесь с нашим https //www back4app com/docs/parse graphql/graphql getting started и также проверьте нашу схему graphql на нашем api playground 1 настройка gui создайте новый файл mutation page dart mutation page dart здесь мы создадим наш gui для ввода данных от пользователя и выполнения задач мутации теперь вставьте следующий код в mutation page dart mutation page 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 } appui() appui() виджет уже был создан для вас итак, мы создали класс с именем mutationpage mutationpage и вернули appui appui виджет в качестве его виджета мы также инициализировали функции обратного вызова для наших текстовых полей, чтобы текст в первом текстовом поле хранился в langname langname , второй в saveformat saveformat и objectid objectid из последнего теперь перейдите к main dart main dart и добавьте параметр floatingactionbutton floatingactionbutton в scaffold() scaffold() виджет класса myhomepage myhomepage и передайте в него следующий код 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 ), это создаст плавающую кнопку, которая перенаправит нас на mutationpage() mutationpage() с нашей главной страницы теперь наш gui настроен вы можете перезапустить ваше приложение, чтобы увидеть gui вот как ваш main dart main 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 создание/добавление данных в базу данных если вы перейдете к graphql configration dart graphql configration dart вы увидите, что мы уже настроили наш graphqlclient graphqlclient и теперь мы можем использовать его в любом месте давайте перейдем к созданию файла database utils dart database utils dart и выполним операцию по созданию данных создайте класс databaseutils{} databaseutils{} и создайте конструктор, который будет принимать параметры данных, с которыми мы будем работать, здесь нам понадобятся langname langname , saveformat saveformat , и objectid objectid 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 } создайте функцию adddata() adddata() которая будет асинхронной функцией для создания данных и инициализации нашего graphqlclient graphqlclient путем инициализации graphqlconfigration graphqlconfigration класса вставьте следующий код в senddata() senddata() функцию 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 } здесь мы инициализировали переменную adddata adddata и передали запрос для создания данных и инициализировали переменную переменную которая будет передавать переменные запроса мы также инициализировали graphqlclient graphqlclient который поможет нам передавать запросы мы можем передавать запросы следующим образом 1 queryresult queryresult = await client query( 2 queryoptions(documentnode gql(adddata), variables variable), 3 ); 4 return queryresult; мы использовали наш graphqlclient graphqlclient экземпляр для написания запроса, который принимает queryoptions() queryoptions() который помогает нам отправлять запрос, как вы видели в последнем уроке результат хранится в queryresult queryresult вот как должен выглядеть ваш database utils dart database utils 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 mutation page dart mutation page dart давайте напишем код для кнопки отправки данных, который можно закодировать внутри senddatabuttonpressed senddatabuttonpressed поскольку нам нужно имя языка и формат сохранения, сначала проверьте, не пустые ли они, а затем создайте экземпляр databaseutils databaseutils и передайте langname langname и saveformat saveformat параметр 1 if(langname isnotempty && saveformat isnotempty){ 2 utils = databaseutils( 3 langname langname, 4 saveformat saveformat , 5 ); 6 } после этого вызовите senddata() senddata() функцию из экземпляра databaseutils databaseutils 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 обновление данных в databaseutils databaseutils создайте функцию future future updatedata() updatedata() инициализируйте string update string update и передайте запрос на обновление и переменные запроса в final variables final variables 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 } теперь инициализируйте наш graphqlclient graphqlclient и отправьте запрос через queryoptions() queryoptions() вот как будет выглядеть ваш код 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 } теперь вернитесь к mutaion page dart mutaion page dart и напишите код в параметре updatebuttonpressed updatebuttonpressed проверьте, что langname langname , objectid objectid и saveformat saveformat не пустые, а затем вызовите функцию updatedata() updatedata() из класса databaseutils databaseutils 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 удаление данных создайте deletedata() deletedata() асинхронную функцию в databaseutils databaseutils и инициализируйте string delete string delete и передайте запрос graphql для удаления данных возьмите финальные переменные финальные переменные и передайте переменные запроса в него 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 } в этом случае нам требуется только objectid objectid строки, которую нужно удалить инициализируйте graphqlclient graphqlclient и отправьте запрос через queryoptions() queryoptions() 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 } в mutationpage mutationpage в deletedatabuttonpressed deletedatabuttonpressed параметр проверяет, что objectid objectid не пустой и не равен null, и вызывает функцию deletedata() deletedata() горячий перезапуск приложения, введите objectid строки, которую нужно удалить, и нажмите кнопку удалить данные это должно удалить конкретную строку из вашего язык язык класса успех ваше приложение наконец то выполнило ваши операции мутации !!! main dart main 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 } database utils dart database utils 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 } mutaion page dart mutaion page 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 } заключение в этом руководстве мы использовали мутации graphql в приложении flutter для создания новых объектов на back4app; обновления объектов на back4app; удаления объектов на back4app на данный момент у вас есть полностью функциональный проект flutter graphql crud, который вы можете использовать в качестве отправной точки для разработки вашего следующего приложения в следующем руководстве мы углубимся в запросы, показывая, как их делать для получения данных из back4app и отображения в нашем приложении flutter хорошего дня!