Flutter
GraphQL
Flutter中的GraphQL CRUD应用指南:前端和后端实现
17 分
使用 graphql 的 flutter crud 应用示例 介绍 在我们的第一篇 flutter graphql 指南中,我们学习了如何使用 graphql api 设置 flutter 项目,以连接和查询 back4app 上的简单数据。此外,我们还学习了如何使用 back4app graphql playground 运行查询/变更,以创建/填充应用数据库。 在本教程中,我们将添加一个功能,通过它我们将直接从我们的应用程序使用 graphql 变更来创建、更新和删除来自 back4app 后端的数据。 目标 在本文结束时,我们希望您能够 使用 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 。 一个用于编写 flutter 代码的 ide,如 android studio 或 vs code。 一个可以在 https //www back4app com/ 。 https //pub dev/packages/graphql flutter 注意:如果您想更好地理解 back4app graphql api,请查看我们的 https //www back4app com/docs/parse graphql/graphql getting started ,并查看我们 api playground 上的 graphql 架构。 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 并在 scaffold() scaffold() 小部件的 myhomepage myhomepage 类中添加一个 floatingactionbutton floatingactionbutton 参数,并将以下代码传递给它: 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 并传递了查询以创建数据,并初始化了 variable variable 将传递查询变量。我们还初始化了 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 参数中编写。由于我们需要 langname 和 saveformat,首先检查它们是否不为空,然后创建一个 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(); 现在你可以 热重启 应用程序,填写两个文本字段并按下发送数据按钮。现在通过按浮动操作按钮返回到查询页面,你可以看到我们的表中添加了一条数据。这就是你的 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 } 结论 在本指南中,我们在 flutter 应用中使用了 graphql 变更来 在 back4app 上创建新对象; 在 back4app 上更新对象; 在 back4app 上删除对象。 此时,您拥有一个功能齐全的 flutter graphql crud 项目,您可以将其作为起点来开发下一个应用。在下一个指南中,我们将深入探讨查询,展示如何进行查询以从 back4app 检索数据并在我们的 flutter 应用中显示。 祝您有美好的一天!