Bạn đã bao giờ tự hỏi làm thế nào để tạo ra một API mạnh mẽ cho phép các client yêu cầu chính xác những gì họ cần chưa? Đó chính là sự kỳ diệu của GraphQL, và với Apollo Server, việc xây dựng một API như vậy đơn giản hơn bạn nghĩ rất nhiều! Nếu bạn đã chán ngán các endpoint cứng nhắc của REST, GraphQL mang lại sự linh hoạt, và Apollo Server là công cụ hàng đầu để biến điều đó thành hiện thực. Trong hướng dẫn mang tính đối thoại này, chúng ta sẽ cùng tìm hiểu cách thiết lập một máy chủ GraphQL sử dụng Apollo Server, từ khởi tạo dự án cho đến kiểm thử các truy vấn (queries) và thay đổi dữ liệu (mutations). Cho dù bạn đang sử dụng JavaScript hay TypeScript, bạn sẽ có một máy chủ hoạt động chỉ trong chốc lát. Hãy cùng bắt đầu và xây dựng một thứ gì đó tuyệt vời với GraphQL và Apollo Server!
Bạn muốn một nền tảng tích hợp, tất cả trong một để Đội ngũ Phát triển của bạn làm việc cùng nhau với năng suất tối đa?
Apidog đáp ứng mọi yêu cầu của bạn, và thay thế Postman với mức giá phải chăng hơn nhiều!
Tại sao chọn GraphQL và Apollo Server?
Trước khi chúng ta bắt tay vào việc, hãy cùng nói chuyện về lý do tại sao GraphQL và Apollo Server lại là một cặp đôi năng động đến vậy. GraphQL, được Facebook phát triển vào năm 2012 và mã nguồn mở vào năm 2015, là một ngôn ngữ truy vấn cho API cho phép các client yêu cầu dữ liệu cụ thể, giảm thiểu tình trạng lấy quá nhiều hoặc quá ít dữ liệu thường thấy trong REST API. Thay vì nhiều endpoint, bạn chỉ có một endpoint thông minh phục vụ các phản hồi được tùy chỉnh. Nó hiệu quả, linh hoạt và hoàn hảo cho các ứng dụng hiện đại với nhu cầu dữ liệu phức tạp.
Và đây là Apollo Server, một máy chủ GraphQL mã nguồn mở, do cộng đồng phát triển từ Apollo GraphQL. Nó sẵn sàng cho môi trường sản xuất, hỗ trợ Node.js và tích hợp liền mạch với các cơ sở dữ liệu như MongoDB hoặc PostgreSQL. Với các tính năng như schema stitching, caching và real-time subscriptions, đây là một giải pháp toàn diện để xây dựng các API có khả năng mở rộng. Hơn nữa, nó thân thiện với người mới bắt đầu nhưng vẫn đủ mạnh mẽ cho các chuyên gia. So với các lựa chọn thay thế như Express-GraphQL, Apollo Server cung cấp khả năng giám sát hiệu suất tốt hơn và thiết lập dễ dàng hơn. Nếu bạn đang xây dựng một blog, trang web thương mại điện tử hoặc backend di động, sự kết hợp này sẽ giúp bạn tiết kiệm thời gian và giảm bớt rắc rối. Hào hứng chưa? Hãy cùng thiết lập dự án của chúng ta!
Thiết lập dự án của bạn bằng JavaScript hoặc TypeScript
Hãy bắt đầu bằng cách tạo nền tảng. Chúng ta sẽ thiết lập một dự án Node.js và cài đặt các gói cần thiết. Bạn có thể chọn JavaScript để đơn giản hoặc TypeScript để đảm bảo an toàn kiểu dữ liệu — cả hai đều hoạt động tốt với Apollo Server.
Bước 1: Khởi tạo dự án
Tạo một thư mục mới:
- Mở terminal của bạn và tạo một thư mục dự án:
mkdir graphql-apollo-server
cd graphql-apollo-server
Khởi tạo Node.js:
- Chạy các lệnh sau:
npm init -y
npm pkg set type="module"
- Thao tác này tạo một tệp
package.json
để quản lý các phụ thuộc và thiết lập dự án sử dụng ES Modules.
Bước 2: Cài đặt các phụ thuộc
Apollo Server yêu cầu hai gói chính: @apollo/server
cho máy chủ và graphql
cho thư viện GraphQL cốt lõi. Đối với TypeScript, chúng ta sẽ thêm các kiểu và một bước xây dựng.
Cài đặt các phụ thuộc:
npm install @apollo/server graphql
Đối với JavaScript:
Chỉ cần thay thế mục scripts
mặc định trong tệp package.json
của bạn bằng các mục type
và scripts
này:
{
// ...etc.
"type": "module",
"scripts": {
"start": "node index.js"
}
// other dependencies
}
Đối với TypeScript (Khuyên dùng):
1. Khởi tạo TypeScript:
npm install --save-dev typescript @types/node
- Tạo một tệp
tsconfig.json
trong thư mục gốc của bạn và chỉnh sửa nó để bao gồm:
{
"compilerOptions": {
"rootDirs": ["src"],
"outDir": "dist",
"lib": ["es2023"],
"target": "es2023",
"module": "esnext",
"moduleResolution": "node",
"esModuleInterop": true,
"types": ["node"]
}
}
2. Cuối cùng, thay thế mục scripts
trong tệp package.json
của bạn bằng các mục type
và scripts
sau:
{
// ...etc.
"type": "module",
"scripts": {
"compile": "tsc",
"start": "npm run compile && node ./dist/index.js"
}
// other dependencies
}

Mẹo chuyên nghiệp: Nếu bạn mới sử dụng TypeScript, nó bổ sung tính an toàn kiểu dữ liệu cho schema và resolvers của bạn, giúp phát hiện lỗi sớm. JavaScript nhanh hơn cho các nguyên mẫu — hãy chọn dựa trên quy mô dự án của bạn.
Bước 3: Tạo tệp máy chủ
Tạo một thư mục src
trong thư mục gốc dự án của bạn và thêm tệp index.ts
(hoặc index.js
cho JavaScript) vào thư mục mới. Đây là nơi chúng ta sẽ định nghĩa schema và resolvers.

Kiểm thử một truy vấn đơn giản
Hãy xây dựng truy vấn đầu tiên của chúng ta — một thông báo "hello" đơn giản. Điều này giới thiệu các định nghĩa kiểu của GraphQL (schema) và resolvers (các hàm tìm nạp dữ liệu).
Định nghĩa GraphQL Schema
Schema là bản thiết kế của API của bạn. Sử dụng thẻ gql
từ graphql-tag
(được bao gồm trong @apollo/server
) để định nghĩa nó.
Trong index.ts
(hoặc index.js
):
import { ApolloServer } from '@apollo/server';
import { startStandaloneServer } from '@apollo/server/standalone';
// Define GraphQL schema
const typeDefs = `
type Query {
hello: String
}
`;
// Define resolvers
const resolvers = {
Query: {
hello: () => "Hello! Welcome to my server",
},
};
// Create and start the server
const server = new ApolloServer({ typeDefs, resolvers });
const { url } = await startStandaloneServer(server, {
listen: { port: 4000 },
});
console.log(`🚀 Server ready at: ${url}`);
Đối với JavaScript, nhập các kiểu:
const { ApolloServer } from '@apollo/server';
const { startStandaloneServer } from '@apollo/server/standalone';
// Rest is the same
Chạy máy chủ
Khởi động máy chủ của bạn:
node index.js # For JavaScript
npm start # For TypeScript
Truy cập http://localhost:4000
trong trình duyệt của bạn. Bạn sẽ thấy GraphQL Playground — một IDE dựa trên web để kiểm thử các truy vấn.

Kiểm thử truy vấn
Trong Playground, chạy truy vấn này ở bảng điều khiển bên trái:
query {
hello
}
Nhấp vào "Execute." Ở bên phải, bạn sẽ thấy:
{
"data": {
"hello": "Hello! Welcome to my server"
}
}

Thành công! Truy vấn đơn giản này minh họa các kiến thức cơ bản của GraphQL: một kiểu Query
với trường hello
trả về một chuỗi. Resolvers là "bộ não" cung cấp dữ liệu — trong trường hợp này, một thông báo tĩnh. Đây là một điểm khởi đầu tuyệt vời để xác minh thiết lập của bạn.
Kiểm thử một truy vấn với kiểu phức tạp
Bây giờ, hãy thêm một số chiều sâu với một kiểu tùy chỉnh. Chúng ta sẽ tạo một kiểu Book
và một truy vấn để tìm nạp danh sách sách. Điều này cho thấy cách GraphQL xử lý dữ liệu có cấu trúc.
Cập nhật Schema
Sửa đổi typeDefs
để bao gồm kiểu Book
:
const typeDefs = gql`
type Book {
title: String
author: String
}
type Query {
books: [Book]
}
`;
Thêm dữ liệu mẫu
Bên dưới typeDefs
, thêm dữ liệu mẫu sau cho kiểu Book
mới của chúng ta:
// Sample data
const books = [
{
title: 'The Awakening',
author: 'Kate Chopin',
},
{
title: 'City of Glass',
author: 'Paul Auster',
},
];
Cập nhật Resolvers
Thay thế nội dung resolver bằng nội dung sau cho kiểu books
:
const resolvers = {
Query: {
books: () => books
}
};
Khởi động lại máy chủ và quay lại Playground.
Kiểm thử truy vấn
Chạy:
query GetBooks {
books {
title
author
}
}
Kết quả:
{
"data": {
"books": [
{
"title": "The Awakening",
"author": "Kate Chopin"
},
{
"title": "City of Glass",
"author": "Paul Auster"
}
]
}
}
Thật tuyệt phải không? Truy vấn này tìm nạp một mảng các đối tượng Book
. GraphQL cho phép client chỉ định chính xác các trường họ muốn — không hơn, không kém. Nếu bạn bỏ qua author
, nó chỉ trả về tiêu đề. Sự linh hoạt này là lý do tại sao GraphQL vượt trội hơn REST đối với các ứng dụng nặng dữ liệu.

Kiểm thử một thay đổi dữ liệu (mutation) để thêm dữ liệu
Truy vấn (Queries) dùng để đọc, nhưng thay đổi dữ liệu (mutations) dùng để ghi. Hãy thêm một thay đổi dữ liệu để tạo một cuốn sách mới, minh họa cách GraphQL xử lý việc tạo dữ liệu.
Cập nhật Schema
Thêm kiểu Mutation
:
const typeDefs = `
type Book {
title: String
author: String
}
type Query {
books: [Book]
}
type Mutation {
createBook(title: String!, author: String!): Book
}
`;
Dấu !
có nghĩa là các trường bắt buộc.
Cập nhật Resolvers
const resolvers = {
Query: {
books: () => books,
},
Mutation: {
createBook: (_: any, { title, author }: { title: string; author: string }) => {
const newBook = { title, author };
books.push(newBook);
return newBook;
}
}
};
Kiểm thử thay đổi dữ liệu (mutation)
Trong Playground, chạy:
mutation CreateBook{
createBook(title: "Harry Potter", author: "J.K Rowling") {
author
title
}
}
Kết quả:
{
"data": {
"createBook": {
"title": "Harry Potter",
"author": "J.K Rowling"
}
}
}

Để xác nhận, chạy lại truy vấn GetBooks
:
query GetBooks {
books {
title
author
}
}
Kết quả:
{
"data": {
"books": [
{
"title": "The Awakening",
"author": "Kate Chopin"
},
{
"title": "City of Glass",
"author": "Paul Auster"
},
{
"title": "Harry Potter",
"author": "J.K Rowling"
}
]
}
}

Cuốn sách mới đã được thêm! Các thay đổi dữ liệu (mutations) trả về dữ liệu đã tạo, cho phép client nhận được phản hồi ngay lập tức. Trong môi trường sản xuất, hãy kết nối với cơ sở dữ liệu như MongoDB để duy trì dữ liệu.
JavaScript vs TypeScript: Chọn cái nào? Đối với các nguyên mẫu nhanh, JavaScript là đủ — ít boilerplate hơn. Nhưng đối với các dự án lớn hơn, TypeScript tỏa sáng với tính an toàn kiểu dữ liệu cho schema và resolvers. TS phát hiện lỗi sớm, giúp máy chủ GraphQL của bạn mạnh mẽ hơn.
Thêm độ phức tạp: ID và truy vấn với đối số
Để làm cho nó thực tế hơn, hãy thêm ID vào sách và một truy vấn để tìm nạp theo tiêu đề.
Cập nhật schema:
const typeDefs = `
type Book {
id: ID!
title: String
author: String
}
type Query {
books: [Book]
book(title: String!): Book
}
type Mutation {
createBook(title: String!, author: String!): Book
}
`;
Cập nhật dữ liệu và resolvers:
// Sample data
const books = [
{
id: 1,
title: 'The Awakening',
author: 'Kate Chopin',
},
{
id: 2,
title: 'City of Glass',
author: 'Paul Auster',
},
];
// Resolvers
const resolvers = {
Query: {
books: () => books,
book: (_: any, { title }: { title: string }) => books.find(book => book.title === title),
},
Mutation: {
createBook: (_: any, { title, author }: { title: string; author: string }) => {
const newBook = { id: books.length + 1, title, author };
books.push(newBook);
return newBook;
}
}
};
Kiểm thử truy vấn:
query GetBook {
book(title: "The Awakening") {
id
title
author
}
}
Kết quả:
{
"data": {
"book": {
"id": "1",
"title": "The Awakening",
"author": "Kate Chopin"
}
}
}
Điều này cho thấy các đối số trong truy vấn, cho phép client lọc dữ liệu hiệu quả.

Các thực hành tốt nhất cho GraphQL với Apollo Server
- Thiết kế Schema: Giữ cho nó theo mô-đun với nhiều tệp.
- Xử lý lỗi: Sử dụng
ApolloError
cho các lỗi tùy chỉnh. - Hiệu suất: Bật bộ nhớ đệm với
@apollo/cache-control
. - Subscriptions: Thêm thời gian thực với
apollo-server-express
. - Giám sát: Sử dụng Apollo Studio để đo lường.
Khắc phục các sự cố thường gặp
- Máy chủ không khởi động? Kiểm tra phiên bản Node (14+) và các phụ thuộc.
- Lỗi truy vấn? Xác minh sự khớp nối giữa schema/resolver.
- Sự cố CORS? Thêm
{ cors: { origin: '*' } }
vào các tùy chọn máy chủ. - Lỗi TS? Cài đặt
@types/graphql
và@types/node
.
Kết luận
Chúng ta đã xây dựng một máy chủ GraphQL mạnh mẽ với Apollo Server, từ các truy vấn chào hỏi đến các thay đổi dữ liệu (mutations). Dù bằng JS hay TS, bạn đã sẵn sàng tạo ra các API linh hoạt. Hãy thử nghiệm, thêm subscriptions và triển khai lên Heroku. GraphQL và Apollo Server là chìa khóa để bạn tạo ra các API hiệu quả!
Apidog cũng hỗ trợ kiểm thử với GraphQL, vì vậy hãy chắc chắn kiểm tra nó hoàn toàn MIỄN PHÍ!
