Cách xây dựng máy chủ GraphQL API với Apollo Server

Ashley Goolam

Ashley Goolam

3 tháng 9 2025

Cách xây dựng máy chủ GraphQL API với Apollo Server

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 GraphQLApollo Server!

💡
Bạn muốn một công cụ kiểm thử API tuyệt vời có thể tạo ra Tài liệu API đẹp mắt?

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!
nút

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 GraphQLApollo 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:

mkdir graphql-apollo-server
cd graphql-apollo-server

Khởi tạo Node.js:

npm init -y
npm pkg set type="module"

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 typescripts 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
{
  "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 typescripts sau:

{
	// ...etc.
    "type": "module",
    "scripts": {
    	"compile": "tsc",
    	"start": "npm run compile && node ./dist/index.js"
    }
	// other dependencies
}
package.json

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.

cấu trúc dự án

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.

sân chơi

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"
  }
}
truy vấn graphql mẫu

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 truy vấn phức tạp hơn

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"
    }
  }
}
kiểm thử thay đổi dữ liệu (mutation)

Để 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"
      }
    ]
  }
}
sách cuối cùng đã được thêm

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ả.

thêm độ phức tạp

Các thực hành tốt nhất cho GraphQL với Apollo Server

Khắc phục các sự cố thường gặp

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. GraphQLApollo 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Í!

nút
hình ảnh apidog

Thực hành thiết kế API trong Apidog

Khám phá cách dễ dàng hơn để xây dựng và sử dụng API