CREATE A GRAPHQL SERVER WITH PHP

Hôm nay mình chia sẻ với mọi người về việc tích hợp graphql-php , các bạn cũng biết graphql giờ các công ty phát triển phần mềm hay sử dụng , bởi vì nó rất thuận tiện ấy. 

Thông thường bạn viết Restful API, bạn phải config nhiều cái route đúng không, chẳng hạn như 
GET /user
GET /user/id
POST /user 
PUT /user/id/update

Nói chung rất là nhiều các Route để request , chính vì thế mà graphql đã mang lại tối ưu hơn , ngắn gọn hơn, chỉ sử dụng một route duy nhất thôi
Các bạn chú ý ở hai chổ này: (query,mutation)
+ query : các bạn viết các câu lệnh truy vấn, lấy dữ liệu VD: getAllPost, getPost, getListComment,....
+ mutation : viết các câu lệnh thao tác sửa đổi thông tin dữ liệu VD: create, update, delete

Nói chung bạn muốn viết điều kiện gì thì viết vậy ::)

VD: viết các câu lệnh truy vấn trong query, request đến API : http://localhost:8000/api.php 

query{
  totalPost
  post(id:172) {
    id,
    title,
    views,
    publish
  },
  posts{
    id,
   title,
    keyword
  }
}

VD: viết câu lệnh trong mutaion để create, update, delete 

mutation{
  updatePost(id:172,views:12,publish:1){
    title,
    views
    publish
  }
  createPost(title:"hoanguyenit",
    keyword:"hoa",des:"hoa",
    image:"hoa.jpg",content:"hoa it",
    user_id:2,views:100,publish:0,slug:"hoa-it"){
    title,
    views,
    publish
    id
  },
  deletePost(id:177)
}

Ở bên trên là các code minh họa thôi , làm thế nào để show dữ liệu ra thì phải kết nối database, viết câu lệnh truy vấn, mới được nhé , ở trên chỉ là câu lệnh yêu cầu gửi đến server thôi

Ở dưới server backend thì ta cần viết câu lệnh truy vấn dữ liệu, thêm , sửa , xóa 

Đầu tiên bạn phải cài một plugin trên google chrome để test GraphQL :ChromeiQL

Các bạn có thể tìm hiểu thêm tại đây : https://webonyx.github.io/graphql-php/getting-started/

Okay, bắt đầu thôi, đầu tiên bạn tạo một thư mục project tên gì cũng được và cài đặt module sau để sử dụng Graphql

composer require webonyx/graphql-php

Sau khi chạy câu lệnh trên, ta sẽ được module rồi. Ta sẽ tạo file api.php trong thư mục project và copy câu lệnh dưới đây

require_once __DIR__ . '/vendor/autoload.php';

use GraphQL\GraphQL;
use GraphQL\Type\Definition\ObjectType;
use GraphQL\Type\Definition\Type;
use GraphQL\Type\Schema;
require "DB.php";

try {

    $config = [
		'host' => 'localhost',
		'database' => 'hoanguyenit',
		'username' => 'root',
		'password' => ''
    ];

    //initialisation of database connection
	  DB::init($config);

    $post = new ObjectType([
        'name' => 'post',
        'fields' => [
            'id'=>['type'=>Type::int()],
            'title'=> ['type' => Type::string()],
            'keyword'=>['type'=>Type::string()],
            'des'=>['type'=>Type::string()],
            'slug'=>['type'=>Type::string()],
            'image'=>['type'=>Type::string()],
            'content'=>['type'=>Type::string()],
            'user_id'=>['type'=>Type::int()],
            'views'=>['type'=>Type::int()],
            'publish'=>['type'=>Type::int()]
        ]
    ]);
    $queryType = new ObjectType([
        'name' => 'Query',
        'fields' => [
            'totalPost' => [
                'type' => Type::int(),
                'resolve' => function($root,$args,$context){
                    /*
                    $conn = new mysqli("localhost", "root", "", "hoanguyenit");
                    $result = mysqli_query($conn,"SELECT count(*) as total FROM `posts`");
                    $data=mysqli_fetch_assoc($result);
                    return $data['total'];
                    */
                    $result = DB::select('SELECT * FROM `posts`');
                    return count($result);
                }
            ],
            'posts' => [
                'type' => Type::listOf($post),
                'args'=>[
                    'title'=> ['type' => Type::string()],
                    'keyword'=>['type' => Type::string()],
                ],
                'resolve' => function ($root, $args, $context) {
                    /*
                    $conn = new mysqli("localhost", "root", "", "hoanguyenit");
                    $result = mysqli_query($conn,"SELECT * FROM `posts` order by id desc");
                    $lists = array();
                    while($rows = mysqli_fetch_array($result)){
                        $lists[] = array('id'=>$rows['id'],'title'=>$rows['title'],'keyword'=>$rows['keyword']);
                    }
                    return $lists;*/
                    $results = DB::select("SELECT * FROM `posts` order by id desc");
                //creation of the total object as a PHP array
                    foreach($results as $row) {
                            $rows[] =array('id'=>$row->id,'title'=>$row->title,'keyword'=>$row->keyword);
                        }
                    return $rows;
                }
            ],
            'post'=>[
                'type'=>$post,
                'args'=>[
                    'id' => ['type'=>Type::int()]
                ],
                'resolve' => function ($root, $args, $context) {
				
                    /*
                    $conn = new mysqli("localhost", "root", "", "hoanguyenit");
                    $result = mysqli_query($conn,"SELECT * FROM `posts` where `id`=".$args['id']);
                    $rows = mysqli_fetch_assoc($result);
                    $lists[] = array('id'=>$rows['id'],'title'=>$rows['title'],'keyword'=>$rows['keyword']);
                    return $lists;*/
					
                    $results = DB::select("SELECT * FROM `posts` where `id`=".$args['id']);
                    return $results[0];

                }
            ],
        ],
    ]);

    $mutationType = new ObjectType([
        'name' => 'Mutation',
        'fields' => [
            'sum' => [
                'type' => Type::int(),
                'args' => [
                    'x' => ['type' => Type::int()],
                    'y' => ['type' => Type::int()],
                ],
                'resolve' => static fn ($calc, array $args): int => $args['x'] + $args['y'],
            ],
            'updatePost'=>[
                'type' =>$post,
                'args' => [
                   'id'=>['type'=>Type::int()],
                   'views'=>['type'=>Type::int()],
                   'publish'=>['type'=>Type::int()]
                ],
                'resolve' => function($root,$args,$context){
                    $sql = "UPDATE posts SET views=:views, publish=:publish WHERE id=:id";

                    $result = DB::execute($sql,$args);
                  
                    $results = DB::select("SELECT * FROM `posts` where `id`=".$args['id']);
                    
                   
                     return $results[0];

                }
            ]
        ],
    ]);



    // See docs on schema options:
    // https://webonyx.github.io/graphql-php/schema-definition/#configuration-options
	
    $schema = new Schema([
        'query' => $queryType,
        'mutation' => $mutationType,
    ]);

    $rawInput = file_get_contents('php://input');
    if ($rawInput === false) {
        throw new RuntimeException('Failed to get php://input');
    }

    $input = json_decode($rawInput, true);
    $query = $input['query'];
    $variableValues = $input['variables'] ?? null;

    $rootValue = ['prefix' => 'You said: '];
    $result = GraphQL::executeQuery($schema, $query, $rootValue, null, $variableValues);
    $output = $result->toArray();
} catch (Throwable $e) {
    $output = [
        'error' => [
            'message' => $e->getMessage(),
        ],
    ];
}

header('Content-Type: application/json; charset=UTF-8');
echo json_encode($output);

Okay, mình sẽ giải thích như thế này cho dễ hình dung! 
Để sử dụng được module vừa composer về thì ta cần gọi nó ra như thế này 

require_once __DIR__ . '/vendor/autoload.php';

Cần khai báo các kiểu Type, để ta cấu hình các trường field, giá trị cần trả về khi request

use GraphQL\GraphQL;
use GraphQL\Type\Definition\ObjectType;
use GraphQL\Type\Definition\Type;
use GraphQL\Type\Schema;

Các bạn xem source code bên trên mình có cấu hình cái Shema và gọi query, mutation. Chính vì thế mà ta phải cần khởi tạo (query, mutation) để cho graphql biết ta cần sử dụng request yêu cầu nào, mà phía client đã gửi đến server

 $schema = new Schema([
        'query' => $queryType,
        'mutation' => $mutationType,
    ]);

Tạo các đối tượng để request truy vấn

$queryType = new ObjectType([]) các bạn xây dựng các phương thức GET truy vấn trong đây (GET)
$mutationType = new ObjectType([]) xây dựng các phương thức thêm, xóa, sửa (POST, PUT,DELETE)

Ở bên trên mình có tạo một kiểu đối tượng là "post", mình muốn dữ liệu được trả về cho client là một đối tượng ('type'=>$post) hoặc một danh sách đối tượng (Type::listOf($post)), nên mình cấu hình type post cho kiểu dữ liệu cần response về

$post = new ObjectType([
        'name' => 'post',
        'fields' => [
            'id'=>['type'=>Type::int()],
            'title'=> ['type' => Type::string()],
            'keyword'=>['type'=>Type::string()],
            'des'=>['type'=>Type::string()],
            'slug'=>['type'=>Type::string()],
            'image'=>['type'=>Type::string()],
            'content'=>['type'=>Type::string()],
            'user_id'=>['type'=>Type::int()],
            'views'=>['type'=>Type::int()],
            'publish'=>['type'=>Type::int()]
        ]
    ]);

Các bạn xem đoạn này, nó sẽ tính tổng và trả về kiểu "int" 'type' => Type::int(),

'totalPost' => [
                'type' => Type::int(),
                'resolve' => function($root,$args,$context){
                    /*
                    $conn = new mysqli("localhost", "root", "", "hoanguyenit");
                    $result = mysqli_query($conn,"SELECT count(*) as total FROM `posts`");
                    $data=mysqli_fetch_assoc($result);
                    return $data['total'];
                    */
                    $result = DB::select('SELECT * FROM `posts`');
                    return count($result);
                }
            ],

'type' => Type::listOf($post) : giúp trả về danh sách cách bài post 

'type'=>$post : hoặc trả về 1 bài viết (post)

+ 'resolve' => function($root,$args,$context,$info)

$root: Đối tượng chứa kết quả được trả về từ trình phân giải trên trường mẹ hoặc trong trường hợp là trường Truy vấn cấp cao nhất, root được truyền từ cấu hình máy chủ. Đối số này cho phép tính chất lồng nhau của các truy vấn GraphQL

$args: Một đối tượng với các đối số được truyền vào trường trong truy vấn.

$context: Đây là đối tượng được chia sẻ bởi tất cả các trình phân giải trong một truy vấn cụ thể và được sử dụng để chứa trạng thái theo yêu cầu, bao gồm thông tin xác thực, các bản sao DataLoader và bất kỳ thứ gì khác cần được tính đến khi giải quyết truy vấn

$info: Đối số này chỉ nên được sử dụng trong các trường hợp nâng cao, nhưng nó chứa thông tin về trạng thái thực thi của truy vấn, bao gồm tên trường, đường dẫn đến trường từ gốc

Bạn xem tiếp phần mutation mình có viết một đối tượng updatePost như sau:

'updatePost'=>[
                'type' =>$post,
                'args' => [
                   'id'=>['type'=>Type::int()],
                   'views'=>['type'=>Type::int()],
                   'publish'=>['type'=>Type::int()]
                ],
                'resolve' => function($root,$args,$context){
                    $sql = "UPDATE posts SET views=:views, publish=:publish WHERE id=:id";

                    $result = DB::execute($sql,$args);
                  
                    $results = DB::select("SELECT * FROM `posts` where `id`=".$args['id']);
                    
                   
                     return $results[0];

                }
            ]

 

Bên trên mình cho kiểu dữ liệu trả về phía client là 'type'=>$post nếu update thành công, 

Chổ $args ta có thể cài đặt các kiểu dữ liệu cho tham số cần khai báo khi update post,

Bạn có thể tìm hiểu sâu hơn về các vấn đề trên nhé!

Còn về vấn đề kết nối truy vấn dữ liệu trong database thì các bạn tùy ý, miễn viết sao mà cảm thấy tối ưu là được! 

Sau khi tìm hiểu sơ qua về Graphql với PHP, bạn có thể tìm hiểu nó với Laravel nhé, khá hay đấy!

create a graphql server with php

 

create a graphql server with php

 

Mình chỉ hiểu sơ qua thôi, các bạn có thể tìm hiểu thêm về Grapqhl tại đây:

Có nhiều người cũng thắc mắc thế này vậy làm sao chúng ta sử dụng graphql trong axio,fetch , mình cũng có tìm hiểu qua về vấn đề này, bạn cũng gọi nó bình thường thôi VD như sau:

fetch('http://localhost/graphql/php/api.php', {
   method: 'POST',
  headers: {
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    query: `
        query fetchPost($id: Int) {
          post(id: $id) {
            title
          }
        }
      `,
    variables: {
      id: 172
    },
  }),
})
  .then((res) => res.json())
  .then((result) => console.log(result));

Bạn chú ý ở chổ : body sẽ có query và variables 

+ query : là chuổi truy vấn Graphql

+ variables : là tham số cần truyền vào 

VD bạn xem hình sau sử dụng chèn tham số trong graphql

 

Bài Viết Liên Quan

Messsage

Nếu bạn thích chia sẻ của tôi, đừng quên nhấn nút !ĐĂNG KÝ