tRPC: Giải pháp API hiện đại cho JavaScript

5 min read

Trong bối cảnh phát triển web ngày càng phức tạp, việc kết nối hiệu quả giữa client và server là thách thức lớn đối với lập trình viên. tRPC (TypeScript Remote Procedure Call) là giải pháp hiện đại giúp tối ưu hóa quá trình này. Bài viết này sẽ giới thiệu chi tiết về kiến trúc của tRPC và các lợi ích nổi bật mà nó mang lại cho các dự án web. sửa lại ngắn hơn

tRPC là gì?

tRPC là một thư viện TypeScript giúp tạo ra các API mạnh mẽ và an toàn với kiểu dữ liệu mà không cần sử dụng REST hay GraphQL. Nó tối ưu hóa sự kết hợp giữa backend và frontend, đặc biệt là khi sử dụng JavaScript và TypeScript ở cả hai phía. Với tRPC, client có thể gọi trực tiếp các controllers của backend như một ứng dụng duy nhất. Thay vì phải định nghĩa rõ ràng các endpoint như trong REST hay sử dụng schema phức tạp như GraphQL, tRPC cho phép định nghĩa các phương thức gọi từ xa (RPC) một cách đơn giản và tự động hóa quá trình kiểm tra kiểu dữ liệu giữa client và server.

Cách triển khai tRPC

1. Tạo Router Instance
Đầu tiên, hãy khởi tạo backend của tRPC. Nên làm điều này trong một tệp riêng và xuất các hàm trợ giúp có thể tái sử dụng thay vì toàn bộ đối tượng tRPC.

server/trpc.ts

import { initTRPC } from '@trpc/server';
 
/**
 * Initialization of tRPC backend
 * Should be done only once per backend!
 */
const t = initTRPC.create();
 
/**
 * Export reusable router and procedure helpers
 * that can be used throughout the router
 */
export const router = t.router;
export const publicProcedure = t.procedure;

Tiếp theo, cần khởi tạo instance router chính, thường được gọi là appRouter, trong đó chúng ta sẽ thêm các procedure sau này. Cuối cùng, cần export kiểu của router để sử dụng sau này trên client.

server/index.ts

import { router } from './trpc';

const appRouter = router({
  // ...
});

// Export type router type signature,
// NOT the router itself.
export type AppRouter = typeof appRouter;

2. Thêm Query Procedure
Sử dụng publicProcedure.query() để thêm một query procedure vào router. Dưới đây là ví dụ tạo một query procedure gọi là userList trả về danh sách người dùng từ cơ sở dữ liệu.

server/index.ts

import { db } from './db';
import { publicProcedure, router } from './trpc';

const appRouter = router({
  userList: publicProcedure
    .query(async () => {
      // Retrieve users from a datasource, this is an imaginary database
      const users = await db.user.findMany();
      return users;
    }),
});

3. Sử Dụng Input Parser để Xác Thực Đầu Vào
Để thực hiện procedure userById, chúng ta cần chấp nhận đầu vào từ client. tRPC cho phép định nghĩa input parser để xác thực và phân tích đầu vào. Bạn có thể định nghĩa input parser của riêng mình hoặc sử dụng thư viện xác thực như zod.

server.ts

import { z } from 'zod';

const appRouter = router({
  // ...
  userById: publicProcedure
    .input(z.string())
    .query(async (opts) => {
      const { input } = opts;
      // Retrieve the user with the given ID
      const user = await db.user.findById(input);
      return user;
    }),
});

4. Thêm Mutation Procedure
Giống như GraphQL, tRPC phân biệt giữa query và mutation procedures. Hãy thêm một mutation gọi là userCreate bằng cách thêm nó vào router object.

server.ts

const appRouter = router({
  // ...
  userCreate: publicProcedure
    .input(z.object({ name: z.string() }))
    .mutation(async (opts) => {
      const { input } = opts;
      // Create a new user in the database
      const user = await db.user.create(input);
      return user;
    }),
});

5. Khởi Chạy API
Bây giờ, khi chúng ta đã định nghĩa router của mình, chúng ta có thể khởi chạy nó. tRPC có nhiều adapter để bạn có thể sử dụng bất kỳ framework backend nào. Để đơn giản, chúng ta sẽ sử dụng standalone adapter.

server/index.ts

import { createHTTPServer } from '@trpc/server/adapters/standalone';

const appRouter = router({
  // ...
});

const server = createHTTPServer({
  router: appRouter,
});

server.listen(3000);

6. Sử Dụng Backend Mới trên Client
Bây giờ chúng ta sẽ chuyển sang mã phía client và tận dụng sức mạnh của tính an toàn kiểu dữ liệu end-to-end. Khi chúng ta import kiểu AppRouter cho client sử dụng, chúng ta đã đạt được tính an toàn kiểu dữ liệu toàn hệ thống mà không làm rò rỉ chi tiết triển khai tới client.

client/index.ts

import { createTRPCClient, httpBatchLink } from '@trpc/client';
import type { AppRouter } from './server'; // 👆 type-only import

// Pass AppRouter as generic here. 👇 This lets the `trpc` object know
// what procedures are available on the server and their input/output types.
const trpc = createTRPCClient<AppRouter>({
  links: [
    httpBatchLink({
      url: 'http://localhost:3000',
    }),
  ],
});

Links trong tRPC tương tự như links trong GraphQL, cho phép chúng ta kiểm soát luồng dữ liệu trước khi gửi tới server. Trong ví dụ trên, chúng ta sử dụng httpBatchLink, tự động gộp nhiều cuộc gọi thành một yêu cầu HTTP duy nhất.

7. Query và Mutation
Bây giờ bạn đã có thể truy cập vào các procedure API trên đối tượng trpc. Ví dụ:

client/index.ts

// Inferred types
const user = await trpc.userById.query('1');

const createdUser = await trpc.userCreate.mutate({ name: 'sachinraja' });

console.log(user);
console.log(createdUser);

Lợi ích của tRPC

  • An Toàn với Kiểu Dữ Liệu: Sử dụng TypeScript và khả năng suy luận kiểu, tRPC giảm thiểu lỗi không khớp kiểu dữ liệu giữa client và server, hữu ích cho các dự án lớn.
  • Dễ Dàng Sử Dụng: Đơn giản hóa quá trình định nghĩa API, chỉ cần định nghĩa các hàm RPC mà không cần tạo endpoint phức tạp hay quản lý schema JSON.
  • Tăng Tốc Độ Phát Triển: Tạo và duy trì API nhanh chóng, các thay đổi trên server được phản ánh ngay lập tức trên client nhờ cơ chế tự động cập nhật kiểu dữ liệu.
  • Hiệu Suất Cao: Không cần layer trung gian phức tạp, tRPC cho phép kết nối trực tiếp từ client tới server mà không thông qua schema validation hay query parsing.

Kết Luận

tRPC mang lại một cách tiếp cận mới mẻ và hiệu quả cho việc phát triển API trong các ứng dụng web hiện đại. Với sự an toàn về kiểu dữ liệu, dễ dàng sử dụng và hiệu suất cao, tRPC đang trở thành một công cụ không thể thiếu cho các lập trình viên JavaScript và TypeScript. Nếu bạn đang tìm kiếm một giải pháp tối ưu cho việc kết nối giữa client và server, hãy thử nghiệm và trải nghiệm sức mạnh của tRPC.

Link tài liệu:

https://trpc.io/docs/quickstart

Avatar photo

Clean Code: Nguyên tắc viết hàm trong lập trình…

Trong quá trình phát triển phần mềm, việc viết mã nguồn dễ đọc, dễ hiểu là yếu tố then chốt để đảm bảo code...
Avatar photo Dat Tran Thanh
3 min read

Leave a Reply

Your email address will not be published. Required fields are marked *