สำหรับ Blog นี้ เรียกว่าลองทำ GraphQL ด้วย dotnet core 8 ครับ โดยใช้ library HotChocolate ชื่อมันดูน่ากินดีนะ 555 โดยของหวาน Set นี้มี 3 Lib
- Hot Chocolate - open-source GraphQL server
- Strawberry Shake - open-source GraphQL client
- Banana Cake Pop - GraphQL GUI
สำหรับ Blog ช่วงนี้จะเน้นตัว Hot Chocolate ก่อนครับ แล้วค่อยขยับไปส่วนอื่นๆ โดยมีหัวข้อดังนี้
มาเริ่มกันเลย
- Simple REST API (GET)
dotnet new webapi --use-controllers -o GraphQLAPI
- เพิ่ม Library เข้าไป
- HotChocolate.AspNetCore ตัว Engine หลักเลยที่จัดการเรื่องนี้
- HotChocolate.AspNetCore.Playground ตัวสร้าง Web คล้าย Postman ให้เราลอง Test ส่ง Request ได้ - คำสั่งที่ใช้เพิ่ม Library
dotnet add package HotChocolate.AspNetCore dotnet add package HotChocolate.AspNetCore.Playground
- มาวางโครงสร้าง Project กันก่อน จะเป็นตามนี้
GraphQLAPI -> Controllers -> GraphQL ---> Query ---> Type -> Services -> Infra ---> Models ---> Repositories
- มาที่ส่วน Infra > Model กันก่อน เราจะลองมาเพิ่มส่วน DTO กันก่อน เอาไว้เก็บข้อมูล ในที่นี้ผมใช้ข้อมูล Suppliers นะ (จริงๆ Copilot) มันแนะนำมา ผมเลยตามเลยครับ
namespace GraphQLAPI.Infra.Model
{
public class SupplierDTO
{
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string Address { get; set; }
public string Email { get; set; }
public string Phone { get; set; }
}
}- ต่อมาเพิ่มส่วนของ Infra > Repository เพิ่ม SupplierRepository ขึ้นมาจัดการ ตอนนี้ผมจะเน้นส่วนยการดึงข้อมูลก่อน เลยเพิ่ม Operation ดึงข้อมูล และให้คืนจากที่ mock ไว้ไปก่อน พวก Add /Edit เดี๋ยวต่อยมาต่อยอดอีก Blog
using GraphQLAPI.Infra.Model;
namespace GraphQLAPI.Infra.Repository
{
public interface ISupplierRepository
{
Task<IEnumerable<SupplierDTO>> GetSuppliers();
Task<SupplierDTO> GetSupplier(int id);
// Task<SupplierDTO> AddSupplier(Supplier supplier);
// Task<SupplierDTO> UpdateSupplier(Supplier supplier);
// Task<SupplierDTO> DeleteSupplier(int id);
}
}namespace GraphQLAPI.Infra.Repository;
using GraphQLAPI.Infra.Model;
using System.Collections.Generic;
public class SupplierRepository: ISupplierRepository
{
private readonly IEnumerable <SupplierDTO> suppliers = new List <SupplierDTO>
{
new SupplierDTO
{
Id = 1,
FirstName = "PingkungA",
LastName = "Agnukginp",
Address = "Thailand, BKK",
Phone = "082-123-4569",
Email = "[email protected]"
},
new SupplierDTO
{
Id = 2,
FirstName = "Faii",
LastName = "Foster",
Address = "Thailand, Chiangrai",
Phone = "082-123-4561",
Email = "[email protected]"
},
new SupplierDTO
{
Id = 3,
FirstName = "Steve",
LastName = "Kook",
Address = "HK, Kowloon",
Phone = "9999999999",
Email = "[email protected]"
}
};
public async Task <IEnumerable <SupplierDTO>> GetSuppliers()
{
return await
Task.FromResult(suppliers);
}
public async Task <SupplierDTO> GetSupplier(int Id)
{
return await Task.FromResult(suppliers.FirstOrDefault(x => x.Id == Id));
}
}
- ต่อมาเพิ่มในส่วนชั้น Service ครับ ล้อกันครับ โดยมีตัว ISupplierService / SupplierService Logic การทำงานตามนี้เลยครับ
namespace GraphQLAPI.Services;
using GraphQLAPI.Infra.Models;
public interface ISupplierService
{
Task<IEnumerable<SupplierDTO>> GetSuppliers();
Task<SupplierDTO> GetSupplier(int id);
// Task<SupplierDTO> AddSupplier(Supplier supplier);
// Task<SupplierDTO> UpdateSupplier(Supplier supplier);
// Task<SupplierDTO> DeleteSupplier(int id);
}namespace GraphQLAPI.Services;
using GraphQLAPI.Infra.Models;
using GraphQLAPI.Infra.Repositories;
public class SupplierService : ISupplierService
{
private readonly ISupplierRepository _supplierRepository;
public SupplierService(ISupplierRepository supplierRepository)
{
_supplierRepository = supplierRepository;
}
public async Task<IEnumerable<SupplierDTO>> GetSuppliers()
{
return await _supplierRepository.GetSuppliers();
}
public async Task<SupplierDTO> GetSupplier(int id)
{
return await _supplierRepository.GetSupplier(id);
}
}- Register Service / Repository ให้ตัว NET8 DI จัดการต่อ ใน program.cs ให้เพิ่ม Code ลงไป ดังนี้
//Repiository builder.Services.AddScoped<ISupplierRepository, SupplierRepository>(); //Service builder.Services.AddScoped<ISupplierService, SupplierService>();
- เพิ่มส่วน Controller
using Microsoft.AspNetCore.Mvc;
using GraphQLAPI.Services;
using GraphQLAPI.Infra.Models;
namespace GraphQLAPI.Controllers;
[Route("api/[controller]")]
[ApiController]
public class SupplierController : ControllerBase
{
private readonly ISupplierService _supplierService;
public SupplierController(ISupplierService supplierService)
{
_supplierService = supplierService;
}
[HttpGet]
public async Task<IEnumerable<SupplierDTO>> GetSuppliers()
{
return await _supplierService.GetSuppliers();
}
[HttpGet("{id}")]
public async Task<SupplierDTO> GetSupplier(int id)
{
return await _supplierService.GetSupplier(id);
}
}ตอนนี้ API ของเราพร้อมใช้งานแล้วครับ
-เพิ่มในส่วนของ GraphQL
จาก Blog เดิม จดจาก Build GraphQL APIs (Go) พบว่าส่วนประกอบของ GraphQL มี Type / Field (method) / Argument(method parameter) / Resolver (Field Resolver)
- ส่วนแรกมาที่ GraphQL > Type มา Mapping ระหว่าง Data Model กับ GraphQL Type
using GraphQLAPI.Infra.Model;
namespace GraphQLAPI.GraphQL.Type
{
public class SupplierType : ObjectType<SupplierDTO>
{
protected override void Configure(IObjectTypeDescriptor <SupplierDTO> descriptor)
{
descriptor.Field(a => a.Id).Type<IdType>();
descriptor.Field(a => a.FirstName).Type<StringType>();
descriptor.Field(a => a.LastName).Type<StringType>();
descriptor.Field(a => a.Address).Type<StringType>();
descriptor.Field(a => a.Phone).Type<StringType>();
}
}
}- ต่อ Map Field (method) / Argument(method parameter) และ Resolver (Field Resolver) โดยที่ Folder GraphQL > Query
using GraphQLAPI.Infra.Models;
using GraphQLAPI.Infra.Repositories;
using GraphQLAPI.Services;
namespace GraphQLAPI.GraphQL.Query
{
public class SupplierGraphQLQuery
{
public async Task<IEnumerable<SupplierDTO>> GetAllSuppliers([Service]ISupplierService supplierService)
{
IEnumerable<SupplierDTO> suppliers = await supplierService.GetSuppliers();
return suppliers;
}
public async Task<SupplierDTO> GetSupplierById([Service]ISupplierService supplierService, int id)
{
SupplierDTO supplier = await supplierService.GetSupplier(id);
return supplier;
}
}
}- ต่อเพิ่มให้ GraphQL สร้าง Schema ออกมา
builder.Services.AddGraphQLServer()
.AddType<SupplierType>()
.AddQueryType<SupplierGraphQLQuery>();- และเปิด Endpoints ให้เข้่าไปเล่นในส่วนของ Playground
app.UsePlayground(new PlaygroundOptions
{
QueryPath = "/graphql",
Path = "/playground"
});
app.MapGraphQL(); //for frontendTest
- ลอง REST API แบบเดิมๆ
@GraphQLAPI_HostAddress = http://localhost:5126
## Rest API ##
### Get Supplier By id ###
GET {{GraphQLAPI_HostAddress}}/api/supplier
### Get all Supplier ###
GET {{GraphQLAPI_HostAddress}}/api/supplier/2
- GraphQL API (Playground) <base_url>/playground

- GraphQL API (.http) - เห็นว่าต้องส่งเป็น Post ทุกรอบนะ และต้องกำหนด X-REQUEST-TYPE: GraphQL โดยที่มี body ตามข้อกำหนดของ GraphQL
@GraphQLAPI_HostAddress = http://localhost:5126
### Get all Supplier ###
POST {{GraphQLAPI_HostAddress}}/graphQL
Content-Type: application/json
X-REQUEST-TYPE: GraphQL
query {
allSuppliers{
id
firstName
lastName
}
}
### Get Supplier By id ###
POST {{GraphQLAPI_HostAddress}}/graphQL
Content-Type: application/json
X-REQUEST-TYPE: GraphQL
query {
supplierById(id:2){
firstName
address
phone
}
}เห็นไหมครับ จริงๆ Graph API ใช่ร่วมกับ REST API เดิมได้นะ

Code เต็มๆอยู่นี้ครับ : pingkunga/net8_graphql_HotChocolate_sample (github.com)
สำหรับ Blog หน้าจะไปในส่วน CREATE / UPDATE / DELETE ครับ
Discover more from naiwaen@DebuggingSoft
Subscribe to get the latest posts sent to your email.



