GraphQL for .NET で Azure Functions + Cosmos DB を試してみた
Azure Functions で .NET を使って GraphQL の QueryとMutation を試してみました。
以下のブログと紹介されているコードを読めば特に説明不要ですね。
追加するするパッケージも以下の3つだけ。
- GraphQL.Server.Core
- Microsoft.Azure.Functions.Extensions
- Microsoft.Azure.WebJobs.Extensions.CosmosDB
デモのInfrastructure内のコードやStartupなどは、ほぼそのまま。モデルやスキーマをちょっと変えて試してみました。
Model と Type
public class Person { public string Id { get; set; } public string Firstname { get; set; } public int Age { get; set; } }
public sealed class PersonType : ObjectGraphType<Person> { public PersonType() { Name = "Person"; Field(x => x.Id, type: typeof(IdGraphType)).Description("ID"); Field(x => x.Firstname).Description("Firstname"); Field(x => x.Age).Description("Age"); } }
Query
public class SampleQuery : ObjectGraphType { private static readonly Uri CollectionUri = UriFactory.CreateDocumentCollectionUri("SampleDB", "People"); public SampleQuery(IDocumentClient documentClient) { // 全件取得 Field<ListGraphType<PersonType>>( "people", resolve: context => documentClient.CreateDocumentQuery<Person>(CollectionUri, null) ); // IDを指定して取得 FieldAsync<PersonType>( "person", arguments: new QueryArguments( new QueryArgument<IdGraphType> { Name = "id", Description = "ID" }), resolve: async context => { var id = context.GetArgument<string>("id"); var uri = UriFactory.CreateDocumentUri("SampleDB", "People", id); var document = await documentClient.ReadDocumentAsync<Person>(uri, new RequestOptions { PartitionKey = new PartitionKey(id) }); return document.Document; }); } }
Mutation
public class SampleMutation : ObjectGraphType { private static readonly Uri CollectionUri = UriFactory.CreateDocumentCollectionUri("SampleDB", "People"); public SampleMutation(IDocumentClient documentClient) { // 追加 FieldAsync<PersonType>( "createPerson", arguments: new QueryArguments( new QueryArgument<NonNullGraphType<StringGraphType>> { Name = "firstname" }, new QueryArgument<NonNullGraphType<IntGraphType>> { Name = "age" }), resolve: async context => { var firstname = context.GetArgument<string>("firstname"); var age = context.GetArgument<int>("age"); var id = Guid.NewGuid().ToString(); var person = new Person { Id = id, Firstname = firstname, Age = age }; await documentClient.CreateDocumentAsync(CollectionUri, person); return person; } ); // 更新 FieldAsync<PersonType>( "updatePerson", arguments: new QueryArguments( new QueryArgument<NonNullGraphType<StringGraphType>> { Name = "id" }, new QueryArgument<StringGraphType> { Name = "firstname" }, new QueryArgument<IntGraphType> { Name = "age" } ), resolve: async context => { var id = context.GetArgument<string>("id"); var firstname = context.GetArgument<string>("firstname"); var age = context.GetArgument<int>("age"); var uri = UriFactory.CreateDocumentUri("SampleDB", "People", id); var person = new Person { Id = id, Firstname = firstname, Age = age }; await documentClient.ReplaceDocumentAsync(uri, person); return person; }); // 削除 FieldAsync<StringGraphType>( "deletePerson", arguments: new QueryArguments( new QueryArgument<NonNullGraphType<StringGraphType>> { Name = "id" } ), resolve: async context => { var id = context.GetArgument<string>("id"); var uri = UriFactory.CreateDocumentUri("SampleDB", "People", id); await documentClient.DeleteDocumentAsync(uri, new RequestOptions { PartitionKey = new PartitionKey(id) }); return id; }); } }
Schema
public class SampleSchema : GraphQL.Types.Schema { public SampleSchema(IDependencyResolver dependencyResolver) : base(dependencyResolver) { Query = dependencyResolver.Resolve<SampleQuery>(); Mutation = dependencyResolver.Resolve<SampleMutation>(); } }
クエリ
GraphiQL はないで、Postman で GraphiQL を指定して動作確認して無事完了。
クエリはこんな感じです。
取得
query { people { id firstname age } }
query { person (id : "00000000-0000-0000-bed0-3d36769a33c0") { id firstname age } }
追加
mutation { createPerson( firstname: "太郎" age: 10 ) { id firstname age } }
更新
mutation { updatePerson( id : "00000000-0000-0000-bed0-3d36769a33c0" firstname: "次郎" age: 20 ) { id firstname age } }
削除
mutation { deletePerson( id : "00000000-0000-0000-bed0-3d36769a33c0" ) }
Subscription
Subscription には対応していないので、通知は SignalR を使うのが簡単ですね。Cosmos DB の変更通知でしたら、以下で紹介されているシナリオと同じです。
ASP.NET Core ではないですが、Azure Functions と Azure SignalR Service は Microsoft Learn で試すことも可能です。