zoukankan      html  css  js  c++  java
  • UWP GraphQL数据查询客户端的实现

    1. 缘起

    Facebook 的移动应用从 2012 年就开始使用 GraphQLGraphQL 规范于 2015 年开源,现已经在多种环境下可用,并被各种体量的团队所使用。

    这个链接可以看到更多的GraphQL使用者。

    2. GraphQL是什么

    英文官网GraphQL is a query language for APIs and a runtime for fulfilling those queries with your existing data.

    中文官网GraphQL 既是一种用于 API 的查询语言也是一个满足你数据查询的运行时。

    个人理解:GraphQL利用了传统的SQL查询,并且以restful api的形式返回数据。

    举个栗子:

    传统的Restful api查询,你要查询一个用户的头像信息,不需要别的信息,那么就是需要利用Http发送给服务区user_id,然后服务器返回给你这个用户的所有信息,比如邮箱、昵称、电话、头像等信息。

    这样以来,如果返回的数据过大的话,可能会因为网络的各种问题导致延迟。

    但是如果像GraphQL,我要查询头像信息,只需要发送

    {
      hero {
        head_url
      }
    }

    那么服务器就只会返回给

    {
      "hero": {
        "head_url": "https://pic.cnblogs.com/face/298986/20150104103009.png"
      }
    }

    嗯,基本就是这样子。仅仅是我的理解,如果不对,麻烦大声告诉我,谢谢。

    官网还有一个gif,更加形象。

    怎么样,可以的吧。

    3. 现存的GraphQL框架

    前面说了,GraphQL仅仅就是一个查询语言,如果想用在自己的项目中,你不可能从头开始研究这个语言,然后手撸自己需要的框架。当然,自己写当然没问题。

    不过官网提供了一些自己写的或者第三方写的库,包括服务器端和客户端的实现。

    详见 ↓

    英文:https://graphql.org/code/ 

    中文:https://graphql.cn/code/

    这其中不得不赞一下一个第三方的Apollo,牛逼的不要不要的。写了Android、iOS、Javascript,就是不写dot net

    .net下不过也有三个:

    第一个好像是微软写的,261 stars。。。不过距离上一个版本发版已经有一年了,这一年有了一些新的bug,但是他们之说下一个版本解决,但是需要多久???God knows。

    第二个是个人开发者写的,80 stars。但是距离他上一次提交代码是三年前了,so。。。放弃吧先

    第三个也是个人开发者写的,26 stars。这个库更新的比较频繁,可以使用。

    4. 一个简单的例子

    拿微软的例子GraphQL.Client说一下吧

    比如就从服务器获取一个pin code

     首先自己先写好mutation句子,类似SQL查询的语句。

    @"mutation{
                        generatePinCode
                    }"

    还是有一点点麻烦的地方,就是自己要写查询语句。

    像刚才提到的Apollo框架,人家都是给你自动生成的,你气不气。

    不过有人在Github提问了,但是微软的人并不打算这么做,可能他们在忙别的事情吧,比如写win10的bug

    然后声明一个GraphQL的Client,指定EndPoint地址。

                GraphQLClient client = new GraphQLClient(new GraphQLClientOptions
                {
                    EndPoint = new Uri("http://dev.xxx.com/api/graphql/guest")
                });

    然后声明GraphQLResponse,来接受服务器返回的消息。

    GraphQLResponse response = await client.PostQueryAsync(
                    @"mutation{
                        generatePinCode
                    }");
    
                if(response.Errors == null)
                {
                    var result = response.GetDataFieldAs<string>("generatePinCode");
                    textBox_Result.Text = textBox_PinCode.Text = result;
                }
                else
                    textBox_Result.Text = "Generate Pin Code Failed";

    看,就是这么简单的例子。

    有人可能好奇,上面的generatePinCode是什么鬼?在哪里出来的。

    其实这个是服务器返回来的数据,我们需要从generatePinCode数据区拿数据而已。

    说到这里,那么就不得不说一下Altair这个神器了。

    Altair中,发送请求,返回来的数据都是包含在data数据体中的。data里面的generatePinCode才是我们真正想要的。

    而通过Altair看出,generatePinCode其实返回了就是一个string类型的字符串。

    那么我们只需要GetDataFieldAs函数,直接反序列化即可。

    5. 一个有一点点复杂的例子

    拿微软的例子GraphQL.Client说一下吧

    比如需要做个用户输入用户名密码登录的例子:

    那么我们写一个简单的xaml代码:

    <TextBox x:Name="textBox_Username" PlaceholderText="user name" BorderThickness="1" Margin="0, 20"/>
    <TextBox x:Name="textBox_pswd" PlaceholderText="password" BorderThickness="1"/>
    <Button Content="Login" Margin="0, 20" Tapped="LoginWithUsernamePassword_Tapped"/>

    然后自己需要写mutation代码,这里我们就查询user 的所有信息。不过这些信息可以按需自己获取。

    @"mutation{
                        login(email:""" + textBox_Username.Text 
                        + @""", password:"""+ textBox_pswd.Text 
                        + @"""){
                        access_token
                        token_type
                        expires_in
                        user{id
                            email
                            nickname
                            email_verified_at
                            password
                            remember_token
                            mobile
                            gender
                            birthdate
                            type
                            avatar_uri
                            avatar_radius_uri
                            status
                            auth_privacy
                            account_type
                            created_at
                            updated_at}
                        }
                        }";

    然后在C#里面响应 LoginWithUsernamePassword_Tapped 时间。

    先声明一个GraphQLClient,指定EndPoint地址。

    GraphQLClient client = new GraphQLClient(new GraphQLClientOptions
                {
                    EndPoint = new Uri("http://dev.xxx.com/api/graphql/guest")
                });

    然后声明GraphQLResponse,来接受服务器返回的消息。

                GraphQLResponse response = await client.PostQueryAsync(query);
                if (response.Errors == null)
                {
                    
                }
                else
                    textBox_Result.Text = "Login With Username Password Failed";

    其实看上面的代码,可以看出,和我们之前用Restful Api的方式一模一样。

    1. 向指定的url发送请求

    2. 获取相应信息

    3. 判断返回的消息是否成功,比如status code等。

    如果GraphQL返回的Response.Errors是空的话,表示查询成功。接下来要对数据进行反序列化处理,以便接下来我们可以直接使用。

                    var result = response.GetDataFieldAs<LoginWithPinCode>("login");
                    textBox_Result.Text = result.access_token;
                    image_Head.Source = new BitmapImage(new Uri(result.user.avatar_radius_uri));

    到这里,可能会有人好奇"login"是怎么来的?

    Altair中,发送请求,返回来的数据都是包含在data数据体中的。data里面的login才是我们真正想要的。

    LoginWithPinCode类是根据返回的login数据,自己定义的model

     

    好了,到此。一个完整的利用用户名密码登录的例子就完成了。

    C#完整代码:

            private async void LoginWithUsernamePassword_Tapped(object sender, TappedRoutedEventArgs e)
            {
                client = new GraphQLClient(new GraphQLClientOptions
                {
                    EndPoint = new Uri("http://dev.xxx.com/api/graphql/guest")
                });
    
                string query = @"mutation{
                        login(email:""" + textBox_Username.Text 
                        + @""", password:"""+ textBox_pswd.Text 
                        + @"""){
                        access_token
                        token_type
                        expires_in
                        user{id
                            email
                            nickname
                            email_verified_at
                            password
                            remember_token
                            mobile
                            gender
                            birthdate
                            type
                            avatar_uri
                            avatar_radius_uri
                            status
                            auth_privacy
                            account_type
                            created_at
                            updated_at}
                        }
                        }";
    
                GraphQLResponse response = await client.PostQueryAsync(query);
    
                if (response.Errors == null)
                {
                    var result = response.GetDataFieldAs<LoginWithPinCode>("login");
                    textBox_Result.Text = result.access_token;
                    image_Head.Source = new BitmapImage(new Uri(result.user.avatar_radius_uri));
                }
                else
                    textBox_Result.Text = "Login With Username Password Failed";
            }

    6. GraphQL使用总结

    如果你的项目突然说要换GraphQL方式查询之类的,不要慌。没听过没关系,它也是一个api,通过结合了SQL查询的方式实现。

    上面的两个例子都是用微软的库实现的。

    如果这三个库都不能满足你的要求,那么就需要用dot net提供的HttpClient来从最底层做起。这样有个好处就是你可以完全按照自己的需要定制。

    像前面提到的Apollo框架,它就存在这样那种的限制。AndroidiOS开发组,在几个schema文件上花费了好大一段时间,又是合并文件又是命名空间啥的。

    不过由于微软的那个库(其实也就是封装了HttpClient,做多了一点处理),封了虽然并没有那么的理想,反而避开了schema这一点。

    如果你从HttpClient,当然更不会存在这种问题了。

  • 相关阅读:
    个人作业——软件工程实践总结&个人技术博客
    个人作业——软件评测
    结对第二次作业——某次疫情统计可视化的实现
    结对第一次—疫情统计可视化(原型设计)
    软工实践寒假作业(2/2)
    软工实践寒假作业(1/2)
    C#MD5判断文件是否修改
    Socket抓包工具WireShark使用
    C#窗体最大化最小化等比例缩放
    QMessageBox
  • 原文地址:https://www.cnblogs.com/hupo376787/p/12076841.html
Copyright © 2011-2022 走看看