Sử dụng TypeScript để tạo API bảo mật với Node.js và Express – Endpoints và Controllers

Tram Ho

Chào các bạn, trong loạt bài về Sử dụng TypeScript để viết API bảo mật với Node.js và Express., mình xin bước sang bài thứ 3 về việc tạo Tạo Endpoints

Tổng quan các bài viết

  1. Giới thiệu và cài đặt ban đầu
  2. Tạo Data Model và Services
  3. Tạo Endpoints
  4. Bảo mật API
  5. Quản lý quyền

⚠️ Các bạn chú ý đọc lần lượt từng bài để nắm rõ nội dung loạt bài nhé.


Lời xin lỗi ngọt ngào

Đầu tiên mình phải xin lỗi các bạn vì trong bài viết đầu tiên mình có nhầm một chút trong cách đặt tên file. Không có gì đáng nghiêm trọng cả, các bạn tìm lại cho mình toàn bộ những nơi có ghi là endtry và đổi lại thành entry giúp mình nhé. Quan trọng khi xong thì các bạn phải chạy lại câu lệnh sau để bundle lại:

Mình đã sửa lại bài viết, nên các bạn mới đọc sẽ không gặp vấn đề này có thể bỏ qua. Có gì khúc mắc các bạn comment xuống dưới mình sẽ giải đáp. 😅


Let’s GOOO

Trong bài này, chúng ta sẽ xem cách sử dụng Typescript và Express để tạo modular controllers cho API.

Trước hết, chúng ta sẽ tạo các endpoint truy cập tới các items để thao tác CRUD tới chúng (trong bài trước mình có nói thay vì sử dụng MongoDB, mình sẽ sử dụng một mảng các item là các đồ ăn được lưu trong mảng ~ RAM).

Tạo Express Controllers sử dụng TypeScript

Thay vì định nghĩa các route trong file entrypoint.ts, các bạn sẽ tạo một Express router dưới dạng một module riêng biệt với tất cả các chi tiết xử lý route của bạn và import nó để sử dụng bất cứ khi nào cần.

Trong thư mục /src/items , tạo file items.router.ts:

Khi một ứng dụng client gửi request tới server của bạn, Express sẽ điều hướng request đó sang cho các function được thiết kế để xử lý (GET hoặc POST). Như vậy, mỗi một function này sẽ định nghĩa một route handle riêng – cái được hiểu là controller

Trong file items.router.ts sẽ có các phần sau :

Dưới phần Required External Modules and Interfaces:

Ở đây, bạn đã import package express và 2 cái internal type definitions của nó (RequestResponse ) sử dụng trong các function callback ở controller.

Bạn cũng cần import các function trong module items.service dưới dạng object ItemService (tránh trùng lặp tên).

Cuối cùng, cần import 2 interface ItemItems dùng để nhập các value trả về từ các function của object ItemService

Tiếp theo, chúng ta sẽ định nghĩa một Express router ở phần Router Definition:

Ở đây, bạn sử dụng class express.Router mục đích để tạo ra để tạo ra một gói modular cho các route handler. Một Express router instance có thể gọi là “app nhỏ” vì nó hoạt động như một middleware và hệ thống route hoàn chỉnh, rất cần thiết cho việc tổ chức kiến trúc của dự án Node.js của bạn thành các thành phần có thể dễ dàng kiểm tra và tái sử dụng.

Song song với đó là bạn sẽ export itemsRouter ra luôn, mặc dù các thuộc tính routing của nó chưa được định nghĩa. Nhưng bất kì thuộc tính nào mà bạn định nghĩa sau đó trong module trên object itemsRouter sẽ có thể được truy cập bởi bất kì module nào import nó.

Trong phần Controller Definitions, bạn sẽ định nghĩa các function tương ứng với một vài chức năng cơ bản CRUD như sau :

Rất dễ hiểu phải không nào. Controller sẽ ủy thác phần lớn các thao tác logic với DB cho các function trong ItemService. Cái hay ở đây là nếu các bạn muốn sử dụng MongoDB hoặc PostgreSQL thì chỉ cần định nghĩa lại logic ở service.

Để hoàn thiện nốt phần controller này, các bạn sẽ đưa vào trong itemsRouter. Mở file entrypoint.ts (trước đó là endtrypoint.ts 😆) lên và import router bên dưới phần Required External Modules:

Tiếp theo, cũng trong file đó, phần App Configuration:

Phương thức app.use() có thể lấy tham số đầu vào là pathcallback để đại diện cho một hoặc nhiều middleware function. Ở đây, Express app sẽ gọi tới các function của middleware itemsRouter (ví dụ khi gọi tới /items)

Test API Endpoints

Với controller trên, chúng ta sẽ thực hiện test từng function.

⚠️ Đừng quên mở 2 terminal riêng biệt và chạy các câu lệnh sau nhé:

npm run webpack

npm start

OK. Mở terminal thứ 3 lên và thử nào:

Lấy toàn bộ menu

flag -i chỉ là dể thêm phần protocol header trong output

Nếu response là HTTP/1.1 200 OK và output gồm 3 object JSON đã khai báo ở file items.service.ts thì OK.

Hoặc các bạn có thể check trực tiếp bằng chrome bằng URL http://localhost:7000/items sẽ ra kết quả như sau:

😀 Để có kết quả như trên các bạn cài thêm extension trong chrome store: JSON FORMATTER nhé.

Lấy món số 1

Output trên terminal cũng ra HTTP/1.1 200 OK và trả về item đầu tiên là OK. Các bạn cũng có thể check bằng trình duyệt bằng URL http://localhost:7000/items/1.

Thêm 1 món ăn

Output: HTTP/1.1 201 Created

Xác nhận lại xem đã create thành công chưa nhé

Update tên món ăn

Output: HTTP/1.1 200 OK

Xác nhận lại kết quả nhé

Xóa món ăn số 2

Output: HTTP/1.1 200 OK

Xử lý Handle Errors

Đơn giản chúng ta sẽ xử lý những request từ client gửi tới nhưng không map với bất kì route nào. Về phần này, mình mới đọc qua một phần khá hay về việc họ xử lý thông qua domain. Để nhanh gọn mình sử dụng class HttpException gói gọn các lỗi liên quan đến các HTTP requests và middleware function, giúp bạn quản lý lỗi chính xác.

Các bạn tạo thêm thư mục common:

Trong thư mục đó tạo thêm file để định nghĩa class HttpException:

Nội dung file :

Tiếp theo sẽ tạo thêm một thư mục middleware:

Trong đó, tạo thêm file

mục đích để xử lý các request lỗi.

Nội dung file error.middleware.ts:

Các function này mang ý nghĩa là: khi các bạn nhận một error kiểu HttpException thì sẽ trả về một error thích hợp dựa trên thuộc tính của nó. Nếu 2 thuộc tính error.statuserror.message được định nghĩa, nó sẽ được bao gồm trong response. Còn không sẽ mặc định lỗi 500 Internal Server Error

Điều quan trọng cần lưu ý là bạn phải cung cấp 4 tham số để xác định hàm ở đây là hàm xử lý error-handling middleware. Sau đó cần xác định object next để duy trì chữ ký error-handling ngay cả khi bạn không sử dụng nó. Còn không, Express sẽ coi object next như một middleware function thông thường và không xử lý bất kì error nào.

Chúng ta cũng cần xét đến điều kiện của router mà không tồn tại. Nó không được coi là lỗi trong Express. Giả sử một mặt hàng hoặc một trang không tồn tại thì cần thông báo chính xác với khách hàng (chứ nó không phải là một errorHandle).

Ví dụ :

Output:

Để customize nội dung hiển thị, bên trong src/middleware, bạn hãy tạo thêm một file notFound.middleware.ts:

Nội dung như sau :

Cuối cùng, cần đưa nó vào trong Express app. Mở file entrypoint.ts, thêm các phần như sau:

Các errorHandler middleware function cần phải được đặt sau cùng, dưới tất cả các controller function. Tuy vậy errorHandler lại ko bắt được lỗi 404 nên sẽ cần thêm middleware function notFoundHandler.

Trước khi test lần các bạn cần tắt server đi và bundle lại webpack:

Thử test với câu lệnh dưới đây:

Output: Resource not found

OK. Vậy là đã xong. Khá dài.

Cảm ơn các bạn đã đọc bài của mình. Bài viết có thể khó hiểu hoặc sai sót, mong các bạn góp ý. Hẹn các bạn ở bài viết tiếp theo về Bảo mật API

Chia sẻ bài viết ngay

Nguồn bài viết : Viblo