在 ASP.NET Core 中使用 GraphQL - Part 1
前言
GraphQL 是一種查詢語言,看起來類似 JSON,而它的查詢結果是 JSON 型別。最初由 Facebook 提出,後來獨立為一個基金會。它的好處在於它的靈活度,對於前端來說,如果要稍微改變從 API 上取得的資料,只要調整一下 GraphQL 的查詢就可以了。 不過也由於它的靈活度,對於開發者而言,也會增加複雜度。
什麼是 GraphQL
要了解 GraphQL 不是件容易的事,所以筆者提供網路上神人做好的範例,大家可以先玩玩看:https://www.graphqlbin.com/v2/mqZgc5
來看一下範例網址一開始的語法:
query {
me {
name
friends {
name
}
posts {
title
likeGivers {
name
}
}
}
}
這段查詢的結果最後會是一個 JSON 結果:
{
"data": {
"me": {
"name": "Fong",
"friends": [
{
"name": "Kevin"
},
{
"name": "Mary"
}
],
"posts": [
{
"title": "Hello World!!",
"likeGivers": [
{
"name": "Fong"
},
{
"name": "Mary"
}
]
},
{
"title": "Love U Too",
"likeGivers": [
{
"name": "Fong"
},
{
"name": "Kevin"
},
{
"name": "Mary"
}
]
}
]
}
}
}
一開始看到查詢跟結果肯定會疑惑,但看了以下的 Schema 後就會清楚了:
directive @cacheControl(
maxAge: Int
scope: CacheControlScope
) on FIELD_DEFINITION | OBJECT | INTERFACE
enum CacheControlScope {
PUBLIC
PRIVATE
}
enum HeightUnit {
METRE
CENTIMETRE
FOOT
}
type Post {
id: ID!
author: User
title: String
content: String
createdAt: String
likeGivers: [User]
}
type Query {
hello: String
me: User
users: [User]
user(name: String!): User
}
scalar Upload
type User {
id: ID!
email: String!
name: String
age: Int
height(unit: HeightUnit = CENTIMETRE): Float
weight(unit: WeightUnit = KILOGRAM): Float
friends: [User]
posts: [Post]
birthDay: String
}
enum WeightUnit {
KILOGRAM
GRAM
POUND
}
當我們看到
type Query {
hello: String
me: User
users: [User]
user(name: String!): User
}
這段時,就能理解前面的查詢,回傳的是一個 User 物件,而 User 的宣告長這樣:
type User {
id: ID!
email: String!
name: String
age: Int
height(unit: HeightUnit = CENTIMETRE): Float
weight(unit: WeightUnit = KILOGRAM): Float
friends: [User]
posts: [Post]
birthDay: String
}
其實前面的查詢欄位有點多,而且欄位又剛好也是類別型態,所以簡化一下:
query {
me {
name
email
}
}
結果如下:
{
"data": {
"me": {
"name": "Fong",
"email": "fong@test.com"
}
}
}
這也說明了,對前端來說,API 的 endpoint 只有一個,查詢時,也可以依據需求取得需要的資料欄位,不必因為 API 的限制硬是取得一整包的資料。
建立 ASP.NET Core 專案並實作 GraphQL
看完以上的範例,這邊就簡單利用 ASP.NET Core 來示範如何做一個簡單的 GraphQL API。
註:這邊只講解 GraphQL 相關的程式碼,資料庫相關的會略過。
首先,安裝相關套件:
- GraphQL
- GraphQL.Server.Transports.AspNetCore
- GraphQL.Server.Ui.Playground
之後準備下列 GraphQL 相關的物件:
- ObjectGraphType (包含 data model 跟 query)
- Schema
首先,這邊示範的資料庫類別如下:
public class Employee
{
[Key]
public int Id { get; set; }
public string Name { get; set; }
public int Age { get; set; }
public int CompanyId { get; set; }
}
public class Company
{
[Key]
public int Id { get; set; }
public string Name { get; set; }
public string Desc { get; set; }
}
然後是對應的 Graph Type:
public EmployeeType()
{
Field(x => x.Id, type: typeof(IdGraphType)).Description("...");
Field(x => x.Name).Description("...");
Field(x => x.Age, type: typeof(IntGraphType)).Description("...");
Field(x => x.CompanyId, type: typeof(IntGraphType)).Description("...");
}
public class CompanyType : ObjectGraphType<Company>
{
public CompanyType()
{
Field(x => x.Id, type: typeof(IdGraphType)).Description("...");
Field(x => x.Name).Description("...");
Field(x => x.Desc).Description("...");
}
}
接下來是 Query 跟 Schema:
public class MainQuery: ObjectGraphType
{
public MainQuery(IEmployeeRepository employeeRepository, ICompanyRepository companyRepository)
{
Name = "Query";
Field<ListGraphType<EmployeeType>>(
"employees",
resolve: context => employeeRepository.GetAll()
);
Field<ListGraphType<CompanyType>>(
"companies",
resolve: context => companyRepository.GetAll()
);
}
}
public class MainSchema : Schema
{
public MainSchema(IDependencyResolver resolver) : base(resolver)
{
Query = resolver.Resolve<MainQuery>();
}
}
之後在 Startup.cs 加入相關設定:
public void ConfigureServices(IServiceCollection services)
{
...
services.AddGraphQL(o => { o.ExposeExceptions = true; })
.AddGraphTypes(ServiceLifetime.Scoped);
// If using IIS:
services.Configure<IISServerOptions>(options =>
{
options.AllowSynchronousIO = true;
});
...
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
...
app.UseGraphQL<MainSchema>();
app.UseGraphQLPlayground(options: new GraphQLPlaygroundOptions());
...
}
之後開啟 https://localhost:[port]/graphql
,輸入下列查詢語法就可以得到 JSON 資料:
query {
employees
{
name
}
}
參考資料