+3

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ác countries 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ục app/code
  • Tạo file registration.php tại đường dẫn app/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ẫn app/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ẫn app/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 ReviewRatingInputCreateReviewInput đễ 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ẫn app/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.phpCreateReview.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

Viblo
Hãy đăng ký một tài khoản Viblo để nhận được nhiều bài viết thú vị hơn.
Đăng kí