尝试使用Xamarin.Forms+AppSync+Lambda获取数据

在中国不同的地区会有不同的背景。

去年,我发布了一款使用Xamarin.Forms开发的KudanAR应用。
尝试使用Xamarin.Forms开发Kudan AR。

經過大約一年的時間,KudanAR圖書館的API金鑰到期日期即將到來。
為了切換API金鑰,每次都需要釋出應用程式,這很麻煩…
因此,我們決定將KudanAR圖書館的API金鑰資料獨立使用Lambda管理,並通過AppSync進行檢索。

环境

主に使用したライブラリバージョンXamarin.Formsv5.0.0.2012GraphQL.Clientv3.2.4GraphQL.Client.Serializer.Newtonsoftv3.2.4
主に使用したAWS機能AppSyncLambda

所创作的东西

我创建了一个样例存储库,重点是从Lambda返回数据并通过AppSync获取响应。
有关AWS方面(AppSync,Lambda),请参阅README.md。
由于本文有很多省略的地方,请参阅详细信息。请查看此处的AppSync演示。

源代码

在这个示例中,当在GraphQL中执行获取所有定义在AppSync中的变量数据时,将返回以下响应。
Lambda本身返回与GetSample键对应的值。

{
  "data": {
    "GetSample": {
      "result": {
        "status_code": 200
      },
      "data": {
        "message": "Hello Xamarin!!!",
        "hoge": "abc",
        "fuga": "あいう",
        "piyo": "xyz",
        "foo": 123,
        "bar": 456
      }
    }
  }
}

如果在Lambda的返回值中,只需要message这个数据,那么可以按以下方式定义GraphQL。
在GraphQL中,如果在行的开头加上#,则该行以后的部分就成为了注释行,可以使用注释行来排除不需要的变量。

query MyQuery($name: String) {
  GetSample(name: $name) {
    data {
      message
    }
  }
}

Model类根据GraphQL的要求进行实现。
这次我们只想针对GraphQL中数据的内部部分。

using System;
using System.Collections.Generic;
using System.Runtime.Serialization;
using System.Text;

namespace AppSyncDemo.Models
{
    [DataContract]
    public class SampleModel
    {
        [DataMember(Name = "message")]
        public string Message { get; set; }
    }
}

以下的源码加载GraphQL,并执行作为查询的操作。
GraphQL作为嵌入资源存储在AppSyncDemo项目的GraphQLs文件夹中。

using AppSyncDemo.Models;
using GraphQL;
using GraphQL.Client.Http;
using GraphQL.Client.Serializer.Newtonsoft;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;

namespace AppSyncDemo.Services
{
    public class AppSyncService
    {
        public static AppSyncService Instance { get; private set; } = new AppSyncService();
        private GraphQLHttpClient GraphQLHttpClient { get; set; }

        public AppSyncService()
        {
            var options = new GraphQLHttpClientOptions
            {
                EndPoint = new Uri(ApiKey.AppSyncApiUrl),
            };
            this.GraphQLHttpClient = new GraphQLHttpClient(options, new NewtonsoftJsonSerializer());
            this.GraphQLHttpClient.HttpClient.DefaultRequestHeaders.Add("x-api-key", ApiKey.AppSyncApiKey);
        }

        public async Task<SampleModel> GetSampleAsync(string name)
        {
            var apiName = "GetSample";
            var variables = new 
            {
                name = name,
            };
            var response = await ExecQueryAsync<SampleModel>(apiName, variables);
            return response;
        }

        /// <summary>
        /// Queryを実行する
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="apiName"></param>
        /// <param name="variables"></param>
        /// <returns></returns>
        public async Task<T> ExecQueryAsync<T>(string apiName, object variables)
        {
            try
            {
                // GraphQL取得
                var resourceId = $"AppSyncDemo.GraphQLs.{apiName}.gql";
                var query = await GetQueryAsync(resourceId);

                // リクエスト作成
                var request = new GraphQLRequest
                {
                    Query = query,
                    OperationName = "MyQuery",
                    Variables = variables,
                };

                // Query実行
                // Mutation実行の場合はSendMutationAsync()を使用
                var response = await this.GraphQLHttpClient.SendQueryAsync<JObject>(request);
                // [apiName]から先が必要かどうかはレスポンスの構造に応じて変更する必要あり
                var json = response.Data[apiName]["data"].ToString();
                var ret = JsonConvert.DeserializeObject<T>(json);

                return ret;
            }
            catch (Exception)
            {
                return default(T);
            }
        }

        /// <summary>
        /// GraphQLを取得
        /// </summary>
        /// <param name="resourceId"></param>
        /// <returns></returns>
        private async Task<string> GetQueryAsync(string resourceId)
        {
            var assembly = Assembly.GetExecutingAssembly();
            using (var stream = assembly.GetManifestResourceStream(resourceId))
            using (var reader = new StreamReader(stream))
            {
                return await reader.ReadToEndAsync();
            }
        }
    }
}

以上是大致的流程。

最初的目的只是获取API密钥数据,所以可以通过API Gateway而不是AppSync来实现,但是因为很少见到相关文章,所以我创建了一个关于AppSync的文章。
说实话,我觉得”获取API密钥的API”这个概念并不太好,但是我决定不过多考虑这个问题。

请参考以下链接。

(Translation: Please refer to the following link.)

sagulati/dotnet-lambda-refarch-imagerecognition
想自如处理C#的非结构化JSON数据

广告
将在 10 秒后关闭
bannerAds