GraphQL cung cấp một lựa chọn thay thế linh hoạt cho phương thức REST cổ điển khi bạn đang xây dựng API.
Một trong số tính năng quan trọng nhất đáng cân nhắc khi thiết kế ứng dụng là kiểu kiến trúc cần sử dụng. Thiết kế API hiệu quả quan trọng trong việc đảm bảo ứng dụng hoạt động trơn tru trong suốt quá trình vận hành.
Kiến trúc RESTful là phương thức tiếp cận phổ biến nhất, nhưng nó có một nhược điểm đáng kể: một kiến trúc endpoint trả về dữ liệu được xác định trước. Thiết kế này có thể dẫn tới giao tiếp kém hiệu quả.
Ngược lại, GraphQL - một giải pháp thay thế cho REST - cung cấp sự linh hoạt hơn bằng cách cho phép bạn chỉ truy vấn dữ liệu cần thiết.
GraphQL API là gì?
GraphQL là một ngôn ngữ truy vấn mà bạn có thể dùng để viết API backend (interface lập trình ứng dụng). Khác REST API, cấp nhiều endpoint cho dữ liệu khác nhau, GraphQL API chỉ có một điểm nhập.
Các client có thể chỉ định dữ liệu họ cần trong truy vấn từ điểm mục nhập duy nhất này, khiến nó trở nên linh hoạt và hiệu quả trong việc chỉ truy xuất dữ liệu cần thiết.
Hiểu đơn giản, GraphQL API triển khai kiến trúc GraphQL được mô tả bởi các thông số kỹ thuật GraphQL. Thiết kế này liên quan tới việc xác định schema, query, mutation mà client có thể tương tác.
- Schema mô tả kiểu dữ liệu và các hoạt động mà API cung cấp. Về cơ bản, schema xác định cấu trúc dữ liệu có sẵn và kiểu truy ván, kiểm thử mà client có thể chạy để chỉnh sửa dữ liệu.
- Query: Client dùng các truy vấn để tìm nạp dữ liệu từ database bằng cách xác định cấu trúc của dữ liệu được yêu cầu. Ngoài ra, client có thể lồng nhiều truy vấn trong một HTTP để nạp dữ liệu liên quan từ nhiều endpoint.
- Mutation là các hoạt động được dùng để chỉnh sửa dữ liệu trên database. Client có thể gửi các truy vấn mutation để tạo, update hoặc xóa dữ liệu.
Thiết lập database MongoDB
Để bắt đầu, tạo một database MongoDB. Sau đó, sao chép chuỗi URL kết nối cơ sở dữ liệu của MongoDB.
Tạo một Apollo Server
Apollo Server là một triển khai máy chủ GraphQL phổ biến, cho phép bạn xây dựng GraphQL API trong môi trường JavaScript, bao gồm Node.js, Express và nhiều hơn thế nữa.
Tạo thư mục cho dự án mới và code bên trong nó:
mkdir graphql-API-mongoDB
cd graphql-API-mongoDB
Tiếp theo, khởi tạo một dự án Node.js mới:
npm init --yes
Lệnh này tạo một file package.json.
Cài đặt các phần phụ thuộc cần thiết
Chạy lệnh sau để cài các gói.
npm install apollo-server graphql mongoose
Cuối cùng, tạo một file index.js trong thư mục gốc của dự án.
Thiết lập Apollo Server
Mở index.js và thêm code bên dưới:
const { ApolloServer } = require('apollo-server');
const mongoose = require('mongoose');
const typeDefs = require("./graphql/typeDefs");
const resolvers = require("./graphql/resolvers");
const server = new ApolloServer({
typeDefs,
resolvers
});
const MONGO_URI = 'mongodb://localhost:27017';
mongoose
.connect(MONGO_URI, {
useNewUrlParser: true,
useUnifiedTopology: true,
})
.then(() => {
console.log(`Db Connected`);
return server.listen({ port: 5000 });
})
.then((res) => {
console.log(`Server running at ${res.url}`);
})
.catch(err => {
console.log(err.message);
});
Code này khởi tạo một máy chủ GraphQL cục bộ bằng thư viện Apollo Server. Sau đó, nó thiết lập một kết nối tới database MongoDB bằng URL kết nối được cung cấp.
Lưu ý cách code chuyển 2 đối số tới phiên bản mới của ApolloServer: typeDefs và resolvers. Chúng xác định kiểu dữ liệu và các hoạt động GraphQL API có thể thực thi.
Sau khi thiết lập kết nối tới database MongoDB, server này bắt đầu lắng nghe trên cổng 5000.
Xác định mô hình dữ liệu
Tạo thư mục mới trong thư mục gốc của thư mục dự án và đặt tên models cho nó. Trong thư mục này, tạo một tên file mới dataModel.js và thêm code sau:
const {model, Schema} = require('mongoose');
const employeeSchema = new Schema({
name: String,
department: String,
salary: String,
});
module.exports = model('Employee', employeeSchema);
Xác định GraphQL Schema
Một schema GraphQL xác định cấu trúc dữ liệu mà bạn có thể truy vấn bằng GraphQL API. Schema cũng vạch ra các query và mutation mà API có thể chạy. Bạn có thể dùng các truy vấn để tìm nạp dữ liệu và mutation để chỉnh sửa nó.
Trong thư mục gốc của dự án, tạo một thư mục mới và đặt tên graphql cho nó. Bên trong thư mục này, thêm 2 file: typeDefs.js và resolvers.js.
Thêm code bên dưới trong file typeDefs.js:
const {gql} = require("apollo-server");
const typeDefs = gql`
type Employee {
id: ID!
name: String
department: String
salary: String
}
input EmployeeInput {
name: String
department: String
salary: String
}
type Query {
getEmployee(id: ID): Employee #return Employee by id
employees: [Employee] #return array of Employees
}
type Mutation {
createEmployee(employeeInput: EmployeeInput): Employee
updateEmployee(id: ID, employeeInput: EmployeeInput): Boolean
deleteEmployee(id: ID): Boolean
}
`;
module.exports = typeDefs;
Code trên dùng hàm gql được cung cấp bởi gói apollo-server để tạo một schema GraphQL cho dữ liệu Employee.
Schema bao gồm 4 nhân tố chính: kiểu dữ liệu cho thông tin nhân viên, kiểu nhập, truy vấn và mutation mà API có thể triển khai.
Xác định Resolvers cho GraphQL API
Resolver là một hàm GraphQL xác định dữ liệu được chuyển khi một client gửi query API để tìm nạp dữ liệu. Về cơ bản, vai trò chính của nó là trích xuất dữ liệu được yêu cầu từ nguồn dữ liệu cụ thể và trả nó về client.
Thêm code bên dưới tới file resolvers.js trong thư mục graphql. Trong trường hợp này, resolver được chỉ định trong các đối tượng Query và Mutation.
Đối tượng Query xác định hai phương thức: employess và getEmployee. Những phương thức này chịu trách nhiệm tìm nạp dữ liệu nhân viên từ database theo yêu cầu của client.
const Employee= require("../models/employeesModel");
// GraphQL Resolvers
const resolvers = {
Query: {
employees: async () => {
try {
const employees = await Employee.find({});
return employees;
} catch (error) {
console.error(error);
throw new Error('Failed to fetch employees');
}
},
getEmployee: async (parent, args) => {
try {
const employee = await Employee.findById(args.id);
return employee;
} catch (error) {
console.error(error);
throw new Error('Failed to fetch employee by ID');
}
},
},
Đối tượng Mutation có 3 phương thức: createEmployee, updateEmployee, và deleteEmployee. Chúng tạo thay đổi tới dữ liệu được lưu trong cơ sở dữ liệu MongoDB.
Mutation: {
async createEmployee (_, { employeeInput: { name, department, salary } }) {
const newEmployee = new Employee({
name: name,
department: department,
salary: salary
});
const response = await newEmployee.save();
console.log(newEmployee);
return {
id: response._id,
...response._doc
}
},
async updateEmployee (_, {id, employeeInput: {name, department, salary}}) {
const updatedEmployee = await Employee.updateOne(
{ _id: id },
{ name, department, salary }
);
if (!updatedEmployee) {
throw new Error(`Employee with ID: ${id} not found`);
}
return true; // Return a boolean value indicating update success
},
async deleteEmployee (_, {id}) {
const deletedEmployee = await Employee.deleteOne({ _id: id });
if (!deletedEmployee || deletedEmployee.deletedCount === 0) {
throw new Error(`Employee with ID ${id} not found`);
}
return true; // Return a boolean value indicating deletion success
},
},
};
module.exports = resolvers;
Cuối cùng, chạy lệnh này để khởi động server:
node index.js
Sau khi đã thiết lập một kết nối database, server này sẽ khởi động trên cổng 5000.
Bạn có thể tiếp tục và kiểm tra tính năng của GraphQL API bằng cách tạo các truy vấn HTTP từ GraphQL playground trong trình duyệt.
Ví dụ, bạn có thể dùng mutation createEmployee để thêm dữ liệu nhân viên mới trong database MongoDB.
Trên đây là cách xây dựng GraphQL API với Apolo Server và MongoDB. Hi vọng bài viết hữu ích với các bạn.