Building GraphQL Server on ASP.NET Core
GET /posts | |
GET /posts/{postId} | |
GET /authors | |
GET /authors/{authorId} | |
GET /tags | |
... |
dotnet new classlib -n PostsQL |
dotnet add package GraphQL |
public class Author | |
{ | |
public Author(int id, string name) | |
{ | |
this.Id = id; | |
this.Name = name; | |
} | |
public int Id { get; set; } | |
public string Name { get; set; } | |
} | |
public class Post | |
{ | |
public Post(int id, string title, string slug, DateTimeOffset published, string authorId, PostStatus status) | |
{ | |
this.Id = id; | |
this.Title = title; | |
this.Slug = slug; | |
this.Published = published; | |
this.AuthorId = authorId; | |
this.Status = status; | |
} | |
public int Id { get; set; } | |
public string Title { get; set; } | |
public string Slug { get; set; } | |
public DateTimeOffset Published { get; set; } | |
public string AuthorId { get; set; } | |
public PostStatus Status { get; set; } | |
} | |
public enum PostStatus | |
{ | |
Created = 1, | |
Published = 2, | |
Deleted = 3 | |
} |
public interface IAuthorService | |
{ | |
Task<Author> GetAuthorByIdAsync(int id); | |
Task<List<Author>> GetAuthorsAsync(); | |
} | |
public class AuthorService : IAuthorService | |
{ | |
private readonly List<Author> _authors; | |
public AuthorService() | |
{ | |
this._authors = new List<Author>() | |
{ | |
new Author(1, "Natasha Romanoff"), | |
new Author(2, "Carol Danvers"), | |
new Author(3, "Jean Grey"), | |
new Author(4, "Wanda Maximoff"), | |
new Author(5, "Gamora"), | |
}; | |
} | |
public async Task<Author> GetAuthorByIdAsync(int id) | |
{ | |
return await Task.FromResult(this._authors.SingleOrDefault(p => p.Id.Equals(id))); | |
} | |
public async Task<List<Author>> GetAuthorsAsync() | |
{ | |
return await Task.FromResult(this._authors); | |
} | |
} | |
public interface IPostService | |
{ | |
Task<Post> GetPostByIdAsync(int id); | |
Task<List<Post>> GetPostsAsync(); | |
} | |
public class PostService | |
{ | |
private readonly List<Post> _posts; | |
public PostService() | |
{ | |
this._posts = new List<Post>() | |
{ | |
new Post(1, "Post #1", "post-1", DateTimeOffset.UtcNow.AddHours(-4), 1, PostStatus.Deleted), | |
new Post(2, "Post #2", "post-2", DateTimeOffset.UtcNow.AddHours(-3), 2, PostStatus.Published), | |
new Post(3, "Post #3", "post-3", DateTimeOffset.UtcNow.AddHours(-2), 3, PostStatus.Published), | |
new Post(4, "Post #4", "post-4", DateTimeOffset.UtcNow.AddHours(-1), 4, PostStatus.Published), | |
new Post(5, "Post #5", "post-5", DateTimeOffset.UtcNow.AddHours(0), 5, PostStatus.Created), | |
}; | |
} | |
public async Task<Post> GetPostByIdAsync(int id) | |
{ | |
return await Task.FromResult(this._posts.SingleOrDefault(p => p.Id.Equals(id))); | |
} | |
public async Task<List<Post>> GetPostsAsync() | |
{ | |
return await Task.FromResult(this._posts); | |
} | |
} |
public class AuthorType : ObjectGraphType<Author> | |
{ | |
public AuthorType() | |
{ | |
this.Field(p => p.Id); | |
this.Field(p => p.Name); | |
} | |
} |
public class PostStatusEnum : EnumerationGraphType | |
{ | |
public PostStatusEnum() | |
{ | |
this.Name = "PostStatus"; | |
this.AddValue(new EnumValueDefinition() { Name = "Created", Description = "Post was created", Value = 1 }); | |
this.AddValue(new EnumValueDefinition() { Name = "Published", Description = "Post has been published", Value = 2 }); | |
this.AddValue(new EnumValueDefinition() { Name = "Deleted", Description = "Post was deleted", Value = 3 }); | |
} | |
} | |
public class PostType : ObjectGraphType<Post> | |
{ | |
private readonly IAuthorService _authorService; | |
public PostType(IAuthorService authorService) | |
{ | |
this._authorService = authorService; | |
this.Field(p => p.Id); | |
this.Field(p => p.Title); | |
this.Field(p => p.Slug); | |
this.Field(p => p.Published); | |
this.FieldAsync<AuthorType>("author", resolve: async c => await this._authorService.GetAuthorByIdAsync(c.Source.AuthorId)); | |
this.Field<PostStatusEnum>("status", resolve: c => c.Source.Status); | |
} | |
} |
public class PostsQuery : ObjectGraphType<object> | |
{ | |
private readonly IPostService _postService; | |
public PostsQuery(IPostService postService) | |
{ | |
this._postService = postService; | |
this.Name = "Query"; | |
this.FieldAsync<ListGraphType<PostType>>( | |
"posts", | |
resolve: async c => await this._postService.GetPostsAsync()); | |
this.FieldAsync<PostType>( | |
"post", | |
arguments: new QueryArguments( | |
new QueryArgument<NonNullGraphType<IntGraphType>>() { Name = "id", Description = "Post ID" }), | |
resolve: async c => await this._postService.GetPostByIdAsync(c.GetArgument<int>("id"))); | |
} | |
} |
public class PostsSchema : Schema | |
{ | |
public PostsSchema(PostsQuery query, IDependencyResolver resolver) | |
{ | |
this.Query = query; | |
this.DependencyResolver = resolver; | |
} | |
} |
dotnet new web -n Server.WebApp |
dotnet add package Microsoft.AspNetCore | |
dotnet add package GraphQL.Server.Core | |
dotnet add package GraphQL.Server.Transports.AspNetCore | |
dotnet add package GraphQL.Server.Transports.WebSockets |
dotnet add package GraphQL-Parser -v 4.1.2 |
dotnet add package GraphQL.Server.Ui.GraphiQL |
dotnet add reference PostsQL |
public class Startup | |
{ | |
public void ConfigureServices(IServiceCollection services) | |
{ | |
services.AddSingleton<IAuthorService, AuthorService>(); | |
services.AddSingleton<IPostService, PostService>(); | |
services.AddSingleton<AuthorType>(); | |
services.AddSingleton<PostType>(); | |
services.AddSingleton<PostStatusEnum>(); | |
services.AddSingleton<PostsQuery>(); | |
services.AddSingleton<PostsSchema>(); | |
services.AddSingleton<IDependencyResolver>(p => new FuncDependencyResolver(type => p.GetRequiredService(type))); | |
services.AddGraphQL() | |
.AddWebSockets() | |
.AddGraphTypes(Assembly.GetAssembly(typeof(PostsSchema))); | |
} | |
} |
public class Startup | |
{ | |
public void Configure(IApplicationBuilder app, IWebHostEnvironment env) | |
{ | |
... | |
app.UseEndpoints(endpoints => | |
{ | |
endpoints.MapGet("/", async context => | |
{ | |
await Task.Run(() => context.Response.Redirect("/ui/graphql", permanent: true)); | |
}); | |
}); | |
app.UseWebSockets(); | |
app.UseGraphQLWebSockets<PostsSchema>(); | |
app.UseGraphQL<PostsSchema>(); | |
app.UseGraphiQLServer(new GraphiQLOptions() { GraphiQLPath = "/ui/graphql", GraphQLEndPoint = "/graphql" }); | |
} | |
} |
dotnet run Server.WebApp |
https://localhost:5001/ |
public void ConfigureServices(IServiceCollection services) | |
{ | |
services.Configure<KestrelServerOptions>(o => o.AllowSynchronousIO = true); | |
... | |
} |
query { | |
post(id: 3) { | |
id, | |
title, | |
slug, | |
author { | |
id, | |
name | |
} | |
} | |
posts { | |
id, | |
title, | |
published | |
} | |
} |
{ | |
"query": "query { post(id: 3) { id, title, slug, author { id, name } } posts { id, title, published } }", | |
"variables": null | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment