使用GraphQL从服务器将数据提取到Flutter应用程序中

GraphQL简介


直到现在,开发人员都依赖REST API来从服务器获取数据,尽管使用REST API存在一些限制,例如灵活性和效率的限制,但它仍然可以正常工作。


GraphQL克服了REST API的这一限制。 GraphQL是用于API的开源数据查询和操作语言,并且是用于使用现有数据执行查询的运行时。 GraphQL由Facebook开发,于2015年首次发布。

开发人员使用REST API通过“基本URL +端点”获取数据, 例如在 http://www.baseurl.com/endpoint, 特定的端点用于获取某些数据,在这种情况下,尽管如果我们仅需要从服务器获取某些数据,则端点将获取配置了端点的完整数据,因此,使用以下方法可能会过度或不足地获取数据REST API。

在GraphQL中,可以通过要求服务器仅发送所需数据而不发送完整数据来解决此问题。

将GRAPHQL集成到Flutter应用中


要在flutter应用中添加/安装graphql库,请打开 “ pubspec.yaml” 从flutter项目结构中添加Graphql pub到dependencies部分下面:

pubspec.yaml 文件:

  
dependencies :

  graphql_flutter : ^3.0.0



执行命令“ packages get”或“ packages update”,以从开发服务器获取GraphQL dart软件包。

现在您可以在Flutter应用中使用GraphQL了!

“ graphql_flutter” pub提供了Graph Query的Widget级实现,要获取该pub的详细信息或其版本日志,请访问 GRAPHQL颤音PUB

graphql函数有两种,即 “ GRAPHQL更改”“ GRAPHQL 查询”,  GraphQL没有任何端点,只有一个api URL,其余的事情由Mutation或Query处理。

突变


graphQL中的突变几乎与REST API的“ POST”相同,通常用于在服务器上写入数据。 Mutation查询修改数据存储中的数据并返回一个值。它可用于插入,更新或删除数据。

查询


graphQL中的查询几乎与REST API的“ GET”相同,它通常用于从服务器读取数据。

实作


要将graphQL用于flutter应用程序,需要将以下文件导入dart代码:



import 'package:graphql_flutter/graphql_flutter.dart'



要使用客户端,首先需要使用链接和缓存对其进行初始化。对于此示例,我们将使用HttpLink作为链接,并使用InMemoryCache作为我们的缓存。

如果您的端点需要身份验证,则可以串联AuthLink,它使用“ Future”变量解析凭据。 (Future变量用于表示将来将可用的潜在值或错误。Future的接收者可以注册在值或错误可用时处理该值或错误的回调),因此您可以异步进行身份验证。

使用Github公共API使用GraphQL的示例示例。



...

import 'package:graphql_flutter/graphql_flutter.dart';

void main() {
final HttpLink httpLink = HttpLink(
uri: '//api.github.com/graphql',
);

final AuthLink authLink = AuthLink(
getToken: () async => 'Bearer ',
// OR// getToken: () => 'Bearer ',);

final Link link = authLink.concat(httpLink);

ValueNotifier client = ValueNotifier(
GraphQLClient(
cache: InMemoryCache(),
link: link,
),
);

...
}

...


       



GRAPHQL提供商


要使用客户端的查询窗口小部件或变异窗口小部件,需要将这些窗口小部件包装到GRAPHQL提供程序窗口小部件中:



...

return GraphQLProvider(
client: client,
child: MaterialApp(
title: 'Flutter Demo',
...
),
);

...

       



变异实施


首先创建MUTATION字符串:



String addStar = """
  mutation AddStar(\$starrableId: ID!) {
    addStar(input: {starrableId: \$starrableId}) {
      starrable {
        viewerHasStarred
      }
    }
  }
""";

       




使用以上突变字符串触发突变:



Mutation(
  options: MutationOptions(
    documentNode: gql(addStar), // this is the mutation string you just created
    // you can update the cache based on results
    update: (Cache cache, QueryResult result) {
      return cache;
    },
    // or do something with the result.data on completion
    onCompleted: (dynamic resultData) {
      print(resultData);
    },
  ),
  builder: (
      RunMutation runMutation,
      QueryResult result,
      ) {
    return FloatingActionButton(
      onPressed: () => runMutation({
      'starrableId': ,
      }),
      tooltip: 'Star',
      child: Icon(Icons.star),
    );
  },
);

       



带有示例的完整dart文件示例:



// bool get starred => repository['viewerHasStarred'] as bool;
// bool get optimistic => (repository as LazyCacheMap).isOptimistic;
        Mutation(
          options: MutationOptions(
            documentNode: gql(starred ? mutations.removeStar : mutations.addStar),
            // will be called for both optimistic 和 final results
            update: (Cache cache, QueryResult result) {
              if (result.hasException) {
                print(['optimistic', result.exception.toString()]);
              } else {
                final Map updated =
                Map.from(repository)
                  ..addAll(extractRepositoryData(result.data));
                cache.write(typenameDataIdFromObject(updated), updated);
              }
            },
            // will only be called for final result
            onCompleted: (dynamic resultData) {
              showDialog(
                context: context,
                builder: (BuildContext context) {
                  return AlertDialog(
                    title: Text(
                      extractRepositoryData(resultData)['viewerHasStarred'] as     bool
                          ? 'Thanks for your star!'
                          : 'Sorry you changed your mind!',
                    ),
                    actions: [
                      SimpleDialogOption(
                        child: const Text('Dismiss'),
                        onPressed: () {
                          Navigator.of(context).pop();
                        },
                      )
                    ],
                  );
                },
              );
            },
          ),
          builder: (RunMutation toggleStar, QueryResult result) {
            return ListTile(
              leading: starred
                  ? const Icon(
                Icons.star,
                color: Colors.amber,
              )
                  : const Icon(Icons.star_border),
              trailing: result.loading || optimistic
                  ? const CircularProgressIndicator()
                  : null,
              title: Text(repository['name'] as String),
              onTap: () {
                toggleStar(
                  { 'starrableId': repository['id'] },
                  optimisticResult: {
                    'action': {
                      'starrable': {'viewerHasStarred': !starred}
                    }
                  },
                );
              },
            );
          },
        );


       


查询实施


首先创建QUERY String:



String readRepositories = """
  query ReadRepositories(\$nRepositories: Int!) {
    viewer {
      repositories(last: \$nRepositories) {
        nodes {
          id
          name
          viewerHasStarred
        }
      }
    }
  }
""";

       



在您的小部件中:


// ...
        Query(
          options: QueryOptions(
            documentNode: gql(readRepositories), // this is the query string you just created
            variables: {
              'nRepositories': 50,
            },
            pollInterval: 10,
          ),
          // Just like in apollo refetch() could be used to manually trigger a refetch
          // while fetchMore() can be used for pagination purpose
          builder: (QueryResult result, { VoidCallback refetch, FetchMore fetchMore }) {
            if (result.hasException) {
              return Text(result.exception.toString());
            }

            if (result.loading) {
              return Text('Loading');
            }

            // it can be either Map or List
            List repositories = result.data['viewer']['repositories']['nodes'];

            return ListView.builder(
                itemCount: repositories.length,
                itemBuilder: (context, index) {
                  final repository = repositories[index];

                  return Text(repository['name']);
                });
          },
        );
// ...

       




这里仅上述graphQL查询中请求的数据仅会在JSON响应中返回,即如下所示



{
   "data": {
      "nodes ": [
         {
            "id": "S1001",
            "name": "User 1",
            "viewerHasStarred": true
         },
         
         {
            "id": "S1002",
            "name": "User 2"
            "viewerHasStarred": false
         },
         
         {
            "id": "S1003",
            "name": "User 3"
            "viewerHasStarred": true
         }
      ]
   }
}


评论

最受关注