Flutter
GraphQL
Flutter с GraphQL: разработка приложения с Back4App
27 мин
скачайте проект flutter graphql с исходным кодом и начните использовать back4app введение в этом учебном пособии мы собираемся создать приложение, которое будет парсить данные из бэкенда back4app через graphql как вы, возможно, знаете, graphql — это язык запросов и манипуляций с данными с открытым исходным кодом для api и среда выполнения для выполнения запросов с существующими данными back4app — это платформа низкого кода как услуга (основанная на open source parse platform), которая помогает разработчикам быстро создавать расширяемые и масштабируемые мобильные и веб приложения цели основная цель — создать простое приложение, которое будет показывать список языков программирования и их формат сохранения в конце этой статьи мы ожидаем, что вы сможете сделать api вызов на back4app с использованием graphql; получить данные из graphql api; получить данные в вашем flutter приложении предварительные требования для завершения этого учебника вам потребуется ide для написания кода flutter, например, android studio или flutter однако мы будем использовать android studio для этого учебника аккаунт на back4app, который можно создать здесь https //www back4app com/ https //pub dev/packages/graphql flutter 1 клонировать проект с github в android studio перейдите в https //github com/templates back4app/flutter graphql , и загрузите zip файл, извлеките его и откройте в вашем ide для flutter чтобы завершить этот шаг, перетащите папку из zip файла на рабочий стол, откройте android studio и затем нажмите на открыть существующий проект android studio директория проекта обычно будет ‘ c \users\username\desktop\back4app graphql starting code ’ но это может быть по разному для разных пользователей откройте проект и перейдите к lib\main dart lib\main dart файлу вы увидите много ошибок, не беспокойтесь, просто нажмите все ‘ получить зависимости ’ и все ошибки исчезнут если нет, то просто нажмите ‘ обновить зависимости ’ код в вашем main dart main dart должен выглядеть так 1 import 'package\ flutter/material dart'; 2 import 'package\ graphql flutter/graphql flutter dart'; 3 import 'consonents dart'; 4 5 void main() { 6 runapp(myapp()); 7 } 8 9 class myapp extends statelesswidget { 10 @override 11 widget build(buildcontext context) { 12 return materialapp( 13 home myhomepage(), 14 ), 15 ); 16 } 17 } 18 class myhomepage extends statefulwidget { 19 @override 20 myhomepagestate createstate() => myhomepagestate(); 21 } 22 23 class myhomepagestate extends state\<myhomepage> { 24 25 @override 26 widget build(buildcontext context) { 27 return safearea( 28 child scaffold( 29 appbar appbar( 30 title text('parsing data using graphql', 31 ), 32 ), 33 body container(), 34 ),); 35 } 36 } если вы откроете приложение сейчас, вы увидите только пустой экран в вашем эмуляторе/устройстве с только одной строкой заголовка ‘парсинг данных с использованием graphql’ мы будем работать с файлом main dart main dart и наши важные значения хранятся в consonents dart consonents dart и мы можем использовать его напрямую оттуда нам потребуется зависимость graphql flutter graphql flutter для использования graphql в нашем приложении библиотека graphql flutter graphql flutter является самой популярной graphql библиотекой для flutter она помогает нам использовать graphql запросы напрямую в нашем коде она предоставляет нам graphqlclient graphqlclient , graphqlprovider graphqlprovider и многие другие полезные виджеты, которые помогают нам парсить данные из нашей базы данных напрямую с помощью graphql, даже не используя streambuilder streambuilder пакет предоставляет нам множество функций, включая подписки кэш в памяти синхронизация кэша в оффлайне оптимистичные результаты загрузка файлов graphql вы можете импортировать его, написав следующий код в файле pubspec yaml pubspec yaml dependencies graphql flutter ^ 3 1 0 смотрите больше о graphql flutter graphql flutter на https //pub dev/packages/graphql flutter все зависимости уже предустановлены, и вы можете перейти к следующему шагу 2 создание бэкенда в back4app после того как вы зарегистрировались на сайте https //www back4app com/ , вы можете перейти к следующему шагу и создать новое приложение нажмите на ‘создать новое приложение’ дайте ему то же имя, что и у вашего проекта, которое здесь ‘back4app graphql’ теперь прокрутите вниз до настройки сервера слева и выберите настройки управление картой parse server, затем выберите опцию ‘3 10 0 parse server 3 10 0’ из списка теперь нажмите кнопку сохранения ниже и подождите, пока она сохранится теперь вернитесь к ядру (слева), выберите консоль api , и выберите консоль graphql из нее это окно, где вы можете писать и тестировать свой код запросов/мутаций graphql давайте перейдем к следующему шагу 3 создание и получение данных через graphql теперь давайте протестируем api graphql на back4app, используя консоль api graphql сначала вставьте следующий запрос в левое поле кода 1 mutation createclass { 2 createclass(input { 3 name "language" 4 schemafields { 5 addstrings \[{name "name"}{name "saveformat"}] 6 } 7 }){ 8 class{ 9 schemafields{ 10 name 11 typename 12 } 13 } 14 } 15 } 16 код выше создаст класс с именем “язык” давайте заполним этот новый класс несколькими строками 1 mutation createobject{ 2 createlanguage(input {fields {name "python", saveformat " py"}}){ 3 language{ 4 name, 5 saveformat 6 } 7 } 8 } если ваша операция успешна, вы увидите это сообщение в правом кодовом блоке на graphql playground 1 { 2 "data" { 3 "createlanguage" { 4 "language" { 5 "name" "python", 6 "saveformat" " py" 7 } 8 } 9 } 10 } мутации используются для создания или внесения изменений в класс запустив вышеуказанную мутацию, мы создадим новый класс с именем language с полями данных name “python” saveformat “ py” повторите процесс и создайте еще два объекта в том же классе для name “c” и saveformat “ c” name “java” и saveformat “ java” мутация для этого будет такой 1 mutation createobject{ 2 createlanguage(input {fields {name "c", saveformat " c"}}){ 3 language{ 4 name, 5 saveformat 6 } 7 } 8 } java 1 mutation createobject{ 2 createlanguage(input {fields {name "java", saveformat " java"}}){ 3 language{ 4 name, 5 saveformat 6 } 7 } 8 } теперь давайте посмотрим на все данные в нашем классе languages для чтения данных мы используем query так что вперед, введите команду ниже 1 query findlanguages{ 2 languages{ 3 count, 4 edges{ 5 node{ 6 name, 7 saveformat 8 } 9 } 10 } 11 } в query findlanguage query findlanguage ‘findlanguage’ — это просто имя для вашей команды запроса, и вы можете назвать его как угодно мы используем find(classname "") find(classname "") команду, чтобы найти все элементы конкретного класса count count , возвращает количество элементов в классе, и все элементы отображаются внутри result result объекта вышеуказанный запрос вернет следующее 1 { 2 "data" { 3 "languages" { 4 "count" 3, 5 "edges" \[ 6 { 7 "node" { 8 "name" "python", 9 "saveformat" " py" 10 } 11 }, 12 { 13 "node" { 14 "name" "c", 15 "saveformat" " c" 16 } 17 }, 18 { 19 "node" { 20 "name" "java", 21 "saveformat" " java" 22 } 23 } 24 ] 25 } 26 } 27 } вы можете увидеть все другие запросы по следующей ссылке https //blog back4app com/graphql on parse/ теперь давайте перейдем к следующему шагу 4 настройка graphql в нашем приложении давайте начнем кодировать наше приложение перед этим вам нужно сделать несколько вещей в вашем lib\consonents dart lib\consonents dart файле скопируйте ссылку graphql, которая находится рядом с кнопкой истории в верхней части окна graphql, и вставьте ее как строку типа kurl теперь перейдите в нижнюю часть страницы и скопируйте коды из http заголовков, скопируйте только коды справа от двоеточия( ) и вставьте их с соответствующими именами в lib\consonents dart lib\consonents dart файл файл должен содержать следующий код 1 string kparseapplicationid= "application id copied from headers"; 2 string kparseclientkey = "client key copied from header"; 3 string kurl= "url copied"; 4 // replace "application id copied from headers", "client key copied from header", "url copied" with real keys/ids copied 5 //from http headers tab теперь перейдите к main dart main dart файлу и перейдите к виджету myapp stateless и добавьте следующий код сразу перед return return materialapp() materialapp() 1 final httplink httplink = httplink( 2 uri kurl, 3 headers { 4 'x parse application id' kparseapplicationid, 5 'x parse client key' kparseclientkey, 6 }, 7 ); httplink из flutter graphql dart и принимает виджет httplink() с двумя параметрами первый это url graphql api на back4app второй это заголовки, необходимые для аутентификации в api back4app после этого раздела вам нужно включить код клиента graphql (объясните, что это), скопируйте код ниже и вставьте его под разделом httplink 1 valuenotifier\<graphqlclient> client = valuenotifier( 2 graphqlclient( 3 cache optimisticcache(dataidfromobject typenamedataidfromobject), 4 link httplink, 5 ), 6 ); теперь мы предоставили метод ссылки и кэша нашему graphqlclient мы сделали это через наш valuenotifier и назвали его client давайте обернем виджет myhomepage(), который является дочерним элементом materialapp, в graphqlprovider и передадим myhomepage() в качестве его клиента добавьте еще один параметр внутри graphqlprovider, а именно client, и передайте client (имя нашего valuenotifier) в него вот как должен выглядеть ваш класс myapp сейчас 1 class myapp extends statelesswidget { 2 @override 3 widget build(buildcontext context) { 4 final httplink httplink = httplink( 5 uri kurl, 6 headers { 7 'x parse application id' kparseapplicationid, 8 'x parse client key' kparseclientkey, 9 //'x parse rest api key' kparserestapikey, 10 },//getheaders() 11 ); 12 valuenotifier\<graphqlclient> client = valuenotifier( 13 graphqlclient( 14 cache optimisticcache(dataidfromobject typenamedataidfromobject), 15 link httplink, 16 ), 17 ); 18 return materialapp( 19 home graphqlprovider( 20 child myhomepage(), 21 client client, 22 ), 23 ); 24 } 25 } давайте вызовем api и получим данные 5 выполнение вызова api теперь мы будем работать над myhomepagestate мы начнем с инициализации типа данных string с именем ‘query’ и присвоим/передадим оператор запроса для поиска всех данных из нашего класса language поскольку запрос многострочный, мы передадим запрос в тройных кавычках вот как это выглядит 1 string query=''' 2 query findlanguages{ 3 languages{ 4 count, 5 edges{ 6 node{ 7 name, 8 saveformat 9 } 10 } 11 } 12 } 13 '''; теперь перейдите к виджету query(), внутри параметра body scaffold, который имеет два свойства опции строитель а затем передайте null для обоих вот как будет выглядеть ваш метод сборки 1 widget build(buildcontext context) { 2 return safearea( 3 child scaffold( 4 appbar appbar( 5 title text('parsing data using graphql', 6 ), 7 ), 8 body query( 9 options null, 10 builder null 11 ), 12 ),); 13 } виджет query() query() помогает нам писать запросы для graphql и поможет нам читать и получать данные мы передадим оператор запроса, который мы взяли в виде строки в опции и создадим виджет с параметром builder поэтому передайте виджет queryoptions() в опции следующим образом 1 options queryoptions( 2 documentnode gql(query), 3 ), 4 запрос передается через параметр documentnode в queryoptions теперь давайте построим с помощью параметра builder метод builder принимает функцию с тремя параметрами, а именно, queryresult result; refetch refetch; fetchmore fetchmore прямо сейчас нам нужно беспокоиться только о queryresult, который дает нам результат нашего запроса, и мы можем получить доступ к данным через result data result data итак, давайте напишем следующий код ниже 1 builder (queryresult result, { refetch refetch,fetchmore fetchmore,}) 2 { 3 if(result data==null){ 4 return center(child text("loading ",style textstyle(fontsize 20 0),)); 5 }else{ 6 return text('success'); 7 } 8 }, в приведенном выше коде мы получаем доступ к данным если данных нет, мы возвращаем текстовый виджет с надписью ‘загрузка…’ иначе мы вернем виджет text() с надписью ‘успех’ вот как должен выглядеть ваш myhomepage myhomepage класс в main dart main dart 1 class myhomepage extends statefulwidget { 2 @override 3 myhomepagestate createstate() => myhomepagestate(); 4 } 5 6 class myhomepagestate extends state\<myhomepage> { 7 string name; 8 string saveformat; 9 string objectid; 10 11 string query = ''' 12 query findlanguages{ 13 languages{ 14 count, 15 edges{ 16 node{ 17 name, 18 saveformat 19 } 20 } 21 } 22 } 23 '''; 24 25 @override 26 widget build(buildcontext context) { 27 return safearea( 28 child scaffold( 29 appbar appbar( 30 title text( 31 'parsing data using graphql', 32 ), 33 ), 34 body query( 35 options queryoptions( 36 documentnode gql(query), 37 ), 38 builder ( 39 queryresult result, { 40 refetch refetch, 41 fetchmore fetchmore, 42 }) { 43 if (result data == null) { 44 return center( 45 child text( 46 "loading ", 47 style textstyle(fontsize 20 0), 48 ), 49 ); 50 } else{ 51 return text('success'); 52 } 53 } 54 ), 55 ), 56 ); 57 } 58 } теперь запустите приложение и подождите несколько секунд после его перезапуска если вы видите ‘success’ на экране, то поздравляем! вы установили соединение и вызвали api 6 получение и отображение данных из api вместо возврата виджета text мы вернем виджет listview\ builder() с оригинальными данными напишите следующий код вместо return text('success') text('success') 1 return listview\ builder( 2 itembuilder (buildcontext context, int index){ 3 return listtile( 4 title text(result data\["languages"]\["edges"]\[index]\["node"]\['name']), 5 trailing text(result data\["languages"]\["edges"]\[index]\["node"]\['saveformat']), 6 ); 7 }, 8 itemcount result data\["languages"]\["edges"] length, 9 ); теперь, если вы посмотрите на экран результата graphql в консоли api back4app, где мы вводили наш метод find, результаты были следующими 1 { 2 "data" { 3 "languages" { 4 "count" 3, 5 "edges" \[ 6 { 7 "node" { 8 "name" "python", 9 "saveformat" " py" 10 } 11 }, 12 { 13 "node" { 14 "name" "c", 15 "saveformat" " c" 16 } 17 }, 18 { 19 "node" { 20 "name" "java", 21 "saveformat" " java" 22 } 23 } 24 ] 25 } 26 } 27 } таким образом, из приведенного выше кода местоположение “python” было “данные” > “ языки” > “количество” > “границы” > “узел” > “имя” также обратите внимание, что имя находится внутри квадратных скобок ‘\[]’ границ, что символизирует, что это первый элемент списка/массива границ итак, нам нужно войти в это местоположение, чтобы получить “python”, и то же самое для всего остального когда мы пишем result data result data , мы входим в “данные” местоположение чтобы указать другие местоположения, мы добавляем \["location name"] \["location name"] к этому таким образом, местоположение “python” будет result data\["languages"]\["edges"]\[0]\["node"]\["name"] result data\["languages"]\["edges"]\[0]\["node"]\["name"] при использовании listview listview , он принимает два параметра, itemcount itemcount , он указывает количество элементов в вызове api, itembuilder itembuilder , он принимает функцию с параметрами (buildcontext context, int index) (buildcontext context, int index) и возвращает список виджетов, в котором мы будем показывать данные здесь мы будем использовать список listtile для отображения данных 1 return listview\ builder( 2 itemcount result data\["languages"]\["edges"] length, 3 itembuilder (buildcontext context, int index){ 4 return listtile( 5 title text(result data\["languages"]\["edges"]\[index]\["node"]\['name']), 6 trailing text(result data\["languages"]\["edges"]\[index]\["node"]\['saveformat']), 7 ); 8 }, 9 10 ); когда мы заменяем text('success') text('success') на вышеуказанный listview\ builder() виджет, мы сначала передаем itemcount, где указываем количество элементов в списке результатов, и поэтому нам больше не нужно об этом беспокоиться в itembuilder мы возвращаем список listtiles, который будет содержать "name" "name" из "languages" "languages" класса и в "saveformat" "saveformat" в конце обратите внимание, что мы использовали индекс вместо любого числа после результата, это то, о чем позаботился itemcount вот как ваш main dart main dart теперь должен выглядеть 1 import 'package\ flutter/material dart'; 2 import 'package\ graphql flutter/graphql flutter dart'; 3 import 'consonents dart'; 4 import 'dart\ ui'; 5 6 void main() { 7 runapp(myapp()); 8 } 9 10 class myapp extends statelesswidget { 11 @override 12 widget build(buildcontext context) { 13 final httplink httplink = httplink( 14 uri 'https //parseapi back4app com/graphql', 15 headers { 16 'x parse application id' kparseapplicationid, 17 'x parse client key' kparseclientkey, 18 }, //getheaders() 19 ); 20 21 valuenotifier\<graphqlclient> client = valuenotifier( 22 graphqlclient( 23 cache optimisticcache(dataidfromobject typenamedataidfromobject), 24 link httplink, 25 ), 26 ); 27 28 return materialapp( 29 home graphqlprovider( 30 child myhomepage(), 31 client client, 32 ), 33 ); 34 } 35 } 36 37 class myhomepage extends statefulwidget { 38 @override 39 myhomepagestate createstate() => myhomepagestate(); 40 } 41 42 class myhomepagestate extends state\<myhomepage> { 43 string name; 44 string saveformat; 45 string objectid; 46 47 string query = ''' 48 query findlanguages{ 49 languages{ 50 count, 51 edges{ 52 node{ 53 name, 54 saveformat 55 } 56 } 57 } 58 } 59 '''; 60 61 @override 62 widget build(buildcontext context) { 63 return safearea( 64 child scaffold( 65 appbar appbar( 66 title text( 67 'parsing data using graphql', 68 ), 69 ), 70 body query( 71 options queryoptions( 72 documentnode gql(query), 73 ), 74 builder ( 75 queryresult result, { 76 refetch refetch, 77 fetchmore fetchmore, 78 }) { 79 if (result data == null) { 80 return center( 81 child text( 82 "loading ", 83 style textstyle(fontsize 20 0), 84 )); 85 } else { 86 return listview\ builder( 87 itembuilder (buildcontext context, int index) { 88 return listtile( 89 title text(result data\["languages"]\["edges"]\[index]\["node"] 90 \['name']), 91 trailing text(result data\["languages"]\["edges"]\[index] 92 \["node"]\['saveformat']), 93 ); 94 }, 95 itemcount result data\["languages"]\["edges"] length, 96 ); 97 } 98 }, 99 ), 100 ), 101 ); 102 } 103 } и наш финальный экран приложения заключение теперь у вас есть приложение flutter, подключенное к graphql api, которое может хранить и извлекать данные на back4app нам не нужно было отдельно кодировать или декодировать данные json, что делает нашу работу проще и быстрее, используя всего несколько строк кода хорошего дня!