Skip to content

Instantly share code, notes, and snippets.

@justinyoo
Last active June 24, 2020 12:53
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save justinyoo/6ed73a24422011564015012b15cc6bd6 to your computer and use it in GitHub Desktop.
Save justinyoo/6ed73a24422011564015012b15cc6bd6 to your computer and use it in GitHub Desktop.
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