Nghiên cứu về GraphQL và ứng dụng trên Magento, NestJS (Phần 2)
Tiếp nối với nội dung của bài viết trước thì ở bài viết này chúng ta sẽ đi sâu vào phần ứng dụng GraphQL vào dự án. Ở phần này chúng ta sẽ tìm hiểu và ứng dụng GraphQL vào Magento kèm với các đoạn code ví dụ.
GraphQL trong Magento 2
- Kể từ phiên bản 2.3 thì Magento bắt đầu hỗ trợ GraphQL cho hệ thống
- Magento xây dựng sẵn một số API hỗ trợ GraphQL có sẵn trong phần core của mình, các API này thường được đặt ở trong module có chứa từ graphql trong thư mục
vendor\magento
- Để truy cập vào GraphQL trên magento thì truy cập ở url
/graphql
VD: Lấy danh sách của cáccountries
trong hệ thống
{
countries {
available_regions {
code
id
name
}
full_name_locale
full_name_english
id
two_letter_abbreviation
three_letter_abbreviation
}
}
Các bước để tạo một module có sử dụng GraphQL Magento
Bước 1: Chuẩn bị môi trường và công cụ
- Cài đặt môi trường phát triển magento 2. Mình sẽ không đi vào chi tiết bước này mọi người có thể tham khảo ở link Installation Guide
- Cài đặt công cụ hỗ trợ GraphQL: có thể sử dụng extension của Chrome như Altair GraphQL Client hoặc ChromeiQL
Bước 2: Khởi tạo module
- Tạo folder
TestModule/GraphQL
ở trong thử mụcapp/code
- Tạo file
registration.php
tại đường dẫnapp/code/TestModule/GraphQL/registration.php
<?php
use Magento\Framework\Component\ComponentRegistrar;
ComponentRegistrar::register(ComponentRegistrar::MODULE, 'TestModule_GraphQL', __DIR__);
- Tạo file
module.xml
tại đường dẫnapp/code/TestModule/GraphQL/etc/module.xml
<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="urn:magento:framework:Module/etc/module.xsd">
<module name="TestModule_GraphQL" setup_version="1.0.0">
<sequence>
<module name="Magento_Backend" />
<module name="Magento_GraphQl" />
<module name="Magento_Review" />
</sequence>
</module>
</config>
Bước 3: Định nghĩa GraphQL Schema
- File schema cho GraphQL của magento sẽ được đặt ở trong thư mục
etc
- Tạo một file
schema.graphqls
tại đường dẫnapp/code/TestModule/GraphQL/etc/schema.graphqls
- Trong GraphQL theo như ta đã nghiên cứu ở bài viết trước thì sẽ có 2 type là type Query để truy vấn dữ liệu và type Mutation để gửi các yêu cầu tác động đễ dữ liệu (thêm, sửa, xóa). Vì vậy ở file
schema.graphqls
chúng ta sẽ định nghĩa 2 type này - Query:
# GraphQl Schema for Query
type Query {
allReviews(
pageSize: Int = 20
@doc(
description: "The maximum number of results to return at once. The default value is 20."
)
currentPage: Int = 1
@doc(
description: "The page of results to return. The default value is 1."
)
): ListReviews
@doc(description: "Return all reviews")
@resolver(class: "TestModule\\GraphQL\\Model\\Resolver\\AllReviews")
listReviewOfProduct(
productId: Int
pageSize: Int = 20
@doc(
description: "The maximum number of results to return at once. The default value is 20."
)
currentPage: Int = 1
@doc(
description: "The page of results to return. The default value is 1."
)
): ListReviews
@doc(description: "Return list review of product")
@resolver(
class: "TestModule\\GraphQL\\Model\\Resolver\\ListReviewOfProduct"
)
}
type ListReviews @doc(description: "Contain a list of reviews") {
items: [Review]! @doc(description: "List of reviews")
page_info: SearchResultPageInfo!
@doc(description: "Metadata for pagination rendering.")
}
type Review @doc(description: "Review info type") {
entity_id: Int! @doc(description: "Review ID")
title: String! @doc(description: "Title of review")
detail: String @doc(description: "Detail of review")
nickname: String! @doc(description: "Nickname of reviewer")
customer_id: Int @doc(description: "Customer ID")
email: String! @doc(description: "Email of reviewer")
created_at: String! @doc(description: "Created at")
}
- Ở đây schema định nghĩa 2 object types là Review bao gồm các trường thông tin của 1 review và ListReviews bao gồm một danh sách các reviews và các thông tin về trang được truy vấn
- Type Query định nghĩa 2 trường là allReviews để lấy thông tin của tất cả các reviews trong hệ thống và listReviewOfProduct để lấy danh sách review của một product thông qua product id.
- Mutation:
# GraphQl Schema for Mutation
type Mutation {
createReview(
input: CreateReviewInput! @doc(description: "An input object to create a review")
) : CreateReviewOutput! @doc(description: "An output after created a review")
@resolver(class: "TestModule\\GraphQL\\Model\\Resolver\\CreateReview")
}
input CreateReviewInput
@doc(
description: "CreateReviewInput"
) {
sku: String! @doc(description: "Product Sku")
nickname: String! @doc(description: "Nickname of reviewer")
email: String @doc(description: "Email of reviewer")
title: String! @doc(description: "Title of review")
details: String @doc(description: "Details of review")
ratings: [ReviewRatingInput!]! @doc(description: "Rating of review")
}
input ReviewRatingInput @doc(description: "Reviewer's rating for a single aspect of a review.") {
id: String! @doc(description: "An encoded rating ID.")
value_id: String! @doc(description: "An encoded rating value ID.")
}
type CreateReviewOutput
@doc(
description: "CreateReviewOutput"
) {
success: Boolean! @doc(description: "True if the review was successfully created")
item: Review @doc(description: "Review created")
}
- Ở đây Schema định nghĩa 2 input ReviewRatingInput và CreateReviewInput đễ xác định các trường sẽ truyền vào để tạo review
- Object type CreateReviewOutput được định nghĩa để xác định các dữ liệu sẽ trả về của Mutation
- Type Mutation định nghĩa trường createReview để cung cấp khả năng tạo review cho user
B4: Tạo Schema Resolver
- Schema Resolver chính là nơi sẽ trực tiếp xử lý các truy vấn ở GraphQL
- Schema Resolver thường được đặt ở thư mục
Model/Resolver
- Tạo một file
AllReviews.php
ở đường dẫnapp/code/TestModule/GraphQL/Model/Resolver/AllReviews.php
<?php
declare(strict_types=1);
namespace TestModule\GraphQL\Model\Resolver;
use Magento\Framework\GraphQl\Query\ResolverInterface;
use Magento\Framework\GraphQl\Config\Element\Field;
use Magento\Framework\GraphQl\Schema\Type\ResolveInfo;
use Magento\Framework\GraphQl\Exception\GraphQlInputException;
use Magento\Review\Model\ResourceModel\Review\Collection as ReviewCollection;
use Magento\Review\Model\ResourceModel\Review\CollectionFactory as ReviewCollectionFactory;
class AllReviews implements ResolverInterface
{
/**
* @var ReviewCollectionFactory
*/
private $reviewCollectionFactory;
/**
* @param ReviewCollectionFactory $reviewCollectionFactory
*/
public function __construct(ReviewCollectionFactory $reviewCollectionFactory)
{
$this->reviewCollectionFactory = $reviewCollectionFactory;
}
/**
* @inheritdoc
*/
public function resolve(
Field $field,
$context,
ResolveInfo $info,
array $value = null,
array $args = null
) {
$this->validateInput($args);
/** @var ReviewCollection */
$reviewCollection = $this->reviewCollectionFactory->create();
$reviewCollection->setPageSize($args['pageSize'])
->setCurPage($args['currentPage']);
$reviewCollection->getSelect()->joinLeft(
['rating' => $reviewCollection->getTable('rating_option_vote')],
'main_table.review_id = rating.review_id',
['rating' => 'value']
);
$data = [
'items' => $reviewCollection->getData(),
'page_info' => [
'page_size' => $reviewCollection->getPageSize(),
'current_page' => $reviewCollection->getCurPage(),
'total_pages' => $reviewCollection->getLastPageNumber()
]
];
return $data;
}
/**
* @throws GraphQlInputException
*/
private function validateInput(array $input)
{
if ($input['currentPage'] < 1) {
throw new GraphQlInputException(__('currentPage value must be greater than 1'));
}
if ($input['pageSize'] < 1) {
throw new GraphQlInputException(__('pageSize value must be greater than 1'));
}
}
}
- Ở file này, method
resolve
sẽ phụ trách xử lý các yêu cầu từ GraphQL do client gửi lên và trả về thông tin tương ứng - Lưu ý: Các class resolver xử lý GraphQL đều phải implement interface
ResolverInterface
- Tương tự với file
ListReviewOfProduct.php
vàCreateReview.php
. Vì các đoạn code khá dài nên mình sẽ không ghi chi tiết code của 2 file đó ở bài viết này, để đọc code của 2 file này mọi người có thể vào link repo mình để bên dưới.
B5: Chạy và kiểm tra query GraphQL
- Chạy các command sau để đảm bảo module được bật
bin/magento module:enable TestModule_GraphQL
bin/magento setup:upgrade
bin/magento setup:di:compile
bin/magento cache:clean
- Kiểm tra query
Query:
{
allReviews(pageSize: 20, currentPage: 1) {
items {
created_at
customer_id
detail
email
entity_id
nickname
title
}
page_info {
current_page
page_size
total_pages
}
}
}
Response:
{
"data": {
"allReviews": {
"items": [
{
"created_at": "2024-01-10 04:52:58",
"customer_id": 1,
"detail": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Morbi in purus ullamcorper, sagittis turpis tristique, ullamcorper lectus. Nullam interdum aliquam porttitor.",
"email": "",
"entity_id": 1,
"nickname": "Customer",
"title": "Lorem ipsum dolor"
},
{
"created_at": "2024-01-12 04:52:58",
"customer_id": 2,
"detail": "Nulla libero leo, sagittis placerat dapibus id, auctor congue mi. Praesent sit amet est sapien. Sed ultricies consequat libero, id porttitor lectus accumsan ut.",
"email": "",
"entity_id": 2,
"nickname": "Steve",
"title": "Praesent sit amet"
},
...
],
"page_info": {
"current_page": 1,
"page_size": 20,
"total_pages": 10
}
Tổng kết
- Ở bài viết này chúng ta đã tìm hiểu cách để sử dụng và phát triển API GraphQL với Magento 2. Magento 2 cung cấp khá nhiều các API với GraphQL mọi người có thể đọc và tìm hiểu kĩ hơn các API được cung cấp ở Link hoặc ở code của magento trong thử mục
vendor/magento
với các module có tên chứa từgraphql
. Đây là link repo code của bài viết này: Link Repo - Ở bài viết tiếp theo của series chúng ta sẽ tiếp tục tìm hiểu cách ứng dụng GraphQL vào NestJS
Tài liệu tham khảo
All rights reserved