Hiểu cơ bản về Express.js thông qua một ví dụ thực tế

Đúng là sẽ dễ dàng tiếp cận và học Nodejs dễ dàng hơn nếu bạn đã từng có kinh nghiệm làm việc với Javascript. Nhưng sự khó khăn và thách thức mà bạn phải đối mặt khi dùng nó để xây dựng backend sẽ hoàn toàn khác so với việc dùng JavaScript như là frontend. Khi tôi học Node, Tôi đã chọn cách khó. Tôi học thông qua e-book, nhưng tutorial và video có sẵn cho tới khi tôi thực sự hiểu tại sao tôi làm được cái mà tôi đang làm. Thực ra có cách tiếp cận dễ hơn. Tôi sẽ dùng một ví dụ về nhà hàng để giải thích 4 phần quan trọng của một Express app cơ bản dành cho những người mới bắt đầu tiếp cận với Nodejs. Express.js là một framework của Nodejs dùng để cấu trúc code và tôi khuyên mọi người nên bắt đầu với nó. Dưới đây là 4 phần chính chúng ta sẽ cùng tìm hiểu:

  • require statements
  • middleware
  • routing
  • starting server

Ở ví dụ so sánh này, bạn sẽ là chủ một nhà hàng đang tìm kiếm 1 vị quản lý - người mà điều hành mọi tiến trình và quản lý các vị trí để nhà hàng hoạt động tốt nhất và khách hàng cảm thấy hài lòng nhất. Chúng ta sẽ cùng nhau tìm hiểu 4 phần trong đoạn code ví dụ trên - đoạn code cơ bản của một Express app. 1. Hiring the manager /thuê 1 quản lý (the require statements) Như tôi đã nói ở trên, bạn là chủ của 1 nhà hàng và bạn cần thuê một người đã có kinh nghiệm quản lý và thành thạo để vận hành công việc hàng ngày của nhà hàng diễn ra suôn sẻ. Nếu bạn muốn việc kinh doanh của nhà hàng diễn ra hiệu quả, bạn cần 1 người có thể giúp nhân viên của mình làm việc với năng lực tốt nhất của họ. Express là một người quản lý như vậy. Phần đầu tiên thì khá đơn giản. Cũng giống như bất kỳ một NPM package khác, bạn cần cài đặt các express modules và sau đó require để load những modules đó:

const express = require('express');
const app = express();

Có một điểm hơi khác package khác đó là bạn cần khai báo:

const app = express();

bởi vì bạn cần 1 biến để lưu lại new Express app. Express không phải là 1 phần mặc định của Node. 2. Making decisions at the restaurant / đưa ra những quyết định (middleware) Những thói quen chung thường xảy ra ở một nhà hàng là gì ? Có 3 cái xuất hiện trong suy nghĩ của tôi đó là:

  • chỗ ngồi khi có khách đến
  • order của khách
  • hóa đơn thanh toán sau bữa ăn

với mỗi cái nêu trên bạn cần phải xem xét một vài điểm trước khi bạn đưa ra hành động. Ví dụ, trước khi bạn mời khách đến chỗ ngồi của họ bạn cần biết:

  • Họ có mặc áo sơ mi và đi giày hay không ? Nếu không thì họ không thể đặt chỗ được
  • Nếu họ muốn ngồi cạnh bar cửa, họ đã 21 tuổi chưa? (Giả sử bạn đang ở Mỹ)

Đây không phải là nhà hàng hay quán bar ở biển. Cũng giống như vậy, code của bạn cần phải đảm bảo rằng request có đúng criteria hay chưa trước khi có thể tiếp tục. Ví dụ khi một user cố login vào app của bạn:

  • Họ đã có tài khoản chưa?
  • Họ có nhập đúng mật khẩu của họ ?

Đó là cách mà định nghĩa về middleware ra đời. Middleware cho phép bạn tạo một action trong bất kỳ một request lên app của bạn và thay đổi nó trước khi trả lại response. Ở nhà hàng, bạn cần một chuỗi các quy định, quy tắc để quyết định rằng bạn có nên tiếp và đặt chỗ cho họ hay không. Giả sử có một đôi đi vào nhà hàng của bạn. Bạn có 1 quy định trước khi đặt bàn cho họ thì phải chắc chắn rằng: họ có mặc áo sơ mi và đi giày không ? Đầu tiên, chúng ta bắt đầu với câu lệnh app.use(). Hiểu đơn giản nó giống như một số rules cần để apply vào cho routes sắp tới của chúng ta. Nó không phải các phương thức GET, POST, PUT hay DELETE. Ở dòng số 4, chúng ta có một anonymous function với 2 tham số đó là req, resnext. Mục đích của hàm này giống như việc chúng ta kiểm tra xem khách hàng ( tương ứng như req ) có mang giày hay áo sơ mi không. Chúng ta cũng cần phải dùng đến function next() ở cuối đoạn code kia bởi vì chúng ta đang validate trang phục ở đây. Sau đó, ở phần routes, chúng ta sẽ cho phép khách đến một bàn cụ thể nào đó. Đoạn code trên thiếu 1 phần quan trọng đó là: path. Nó là một chuỗi cụ thể đi kèm với request. Bởi vì nó thiếu path nên sẽ chạy đoạn code trên với từng request một. Bạn hãy tưởng tượng rằng: Khi khách đến nhà hàng và vào nhà hàng, order đồ ăn, yêu cầu chúng ta kiểm tra,...lúc đó thì nhân viên sẽ phải thực hiện việc nhìn tổng quát về trang phục của họ. Chúng ta sửa một chút ở dòng số 4 bằng cách thêm path cụ thể đó là '/table'. Bây giờ thì đoạn code sẽ chỉ chạy khi có request đến với đường dẫn là '/table'. Dưới đây là hình ảnh giải thích chi tiết: 3. Executing common routines/ nhóm những công việc hàng ngày (routing) Chúng ta tiếp tục với ví dụ về việc đặt chỗ khi có khách đến nhà hàng ở trên. Ở trên chúng ta mới chỉ biết cách validate xem rằng khách hàng có đủ điều kiện để đặt chỗ hay không. Chứ chưa biết làm sao để chỉ họ đến một bàn cụ thể và mời họ ngồi. Đó là lý do có sự xuất hiện của routes. Routes cho phép chúng ta tạo một hành động cụ thể dựa vào path. Chúng ta có một số phương thức (actions) như GET, POST, PUT, DELETE, nhưng chúng ta sẽ chỉ tìm hiểu GET và POST ở ví dụ này. Chúng ta sẽ cần tạo một GET request để chọn một bàn cụ thể và mời khách ngồi. Phương thức GET sẽ không thay đổi hay động chạm gì tới việc thêm sửa dữ liệu trong database. Nó sẽ chỉ lấy dữ liệu dựa trên tham số cụ thể. Chúng ta sẽ tạo một phương thức để đặt bàn cho một bữa tiệc dành cho 2 người như sau:

app.get('/table/:amount', (req, res) => {
   let party = req.params.amount;
   res.send(`Chúng tôi đang tìm bàn dành cho ${party} người`);
})

Ở dòng đầu, ta định nghĩa phương thức để tìm 1 bàn khi khách request thông qua đường dẫn "/table". Cũng giống như ví dụ về middleware ở trên, ta có sẵn các tham số request và response. Nó cũng có một tham số gọi là amount. Trong ví dụ này là 2 (bàn dành cho 2 người). Thực tế, mọi thứ sau khai báo function ở dòng đầu thực chất là middleware vì nó ảnh hưởng đến request người dùng. Bạn sẽ thấy rõ hơn ở biểu đồ phía dưới. Ở dòng tiếp theo, ta lấy số người thông qua parameter của object request. Nó không được khai báo ở bất kì đâu vì request tới từ user, và ta không có bất kì front-end code nào. Vậy request có thể trông như này nếu đây là 1 app thật:

req = {
  params: {
    amount: 2;
  }
}

Cuối cùng ở dòng cuối, ta gửi 1 response về cho customer: chúng tôi đang tìm một bàn phù hợp. Đây là biểu đồ: Making your restaurant efficient (router) Giờ bạn có thể lần theo đường từ request tới response. Nhưng khi app mở rộng và phát triển lớn hơn, bạn sẽ không muốn viết những rules riêng cho mỗi đường dẫn. Bạn sẽ thấy rằng một số route chỉa sẻ cùng rules, vậy nên bạn cần tìm cách để apply những rules đó cho nhiều đường dẫn. Nói về đặt chỗ, bạn có thể đặt chỗ cho khách tại bar hoặc tại bàn. Những thứ có cùng rules như áo phông + giày, nhưng đặt chỗ ở bar yêu cầu mọi thành viên phải đủ 21 tuổi. Và về phục vụ khách, bạn sẽ cần dùng phương thức khác biệt một chút cho món khai vị, món chính, và bữa tối. Nhưng 3 routes này cũng có nhiều điểm chung. Đây là nơi router xuất hiện. Router cho phép bạn nhóm các route lại để mà bạn có thể tạo các common rules. Chúng ta sẽ tạo middleware và overwrite code phía trên: Tôi sẽ nói về từng phần riêng. Ở dòng 4, ta khai báo router với built-in của Express. Ở dòng 6 và 14, ta có seatingRouter.use() thay cho app.use() để chỉ ra rằng middleware này chỉ liên kết tới seatingRouter routes. Cuối cùng, ở dòng 21, ta thêm nhiều middleware hơn để cho thấy rằng mọi seatingRouter route đều bắt đầu với "/seating". Vậy, nếu một người muốn đặt chỗ ở bar, đường dẫn đầy đủ sẽ là "/seating/bar". Hình như có gì sai sai, vì bạn sẽ nghĩ đường dẫn được xác định khi bạn tạo router ở dòng 4. Điều đó là bình thường. Đây chính là nó ở diagram form: Và khi bạn thêm một phương thức GET, nó sẽ được chèn lên phía trên dòng cuối cùng nơi bạn gán route cho router. 4. Opening for business (ports) / khai trương cửa hàng Ok, phần cuối. Đến đây, bạn đã thuê được 1 quản lý, xác định được điều cần làm trước khi chấp nhận những yêu cầu của khách, và quyết định được cần phải làm gì với yêu cầu của khách cụ thể khi cần. Bây giờ, bận chỉ cần quyết định nơi để tất cả những điều này diễn ra. Server có các port mà như là địa chỉ của nhà hàng. Vì server có thể xử lý nhiều kiểu nhà hàng ( hoặc server-side scripts) cùng lúc, bạn cần cho nó biết mỗi script nên chạy ở chỗ nào.

app.listen(3000, function () {
    console.log('Nhà hàng đã khai trương và đón khách ở địa chỉ 3000 !');
});

Trong ví dụ trên, server của chúng ta chạy trên port là 3000. Vậy nếu bạn gõ: https://localhost:3000/ vào trình duyệt, và bạn đang chạy Node app, server sẽ biết cách vận hành các script cụ thể. Trong trường hợp này, miễn là bạn nhập đúng URL, bạn sẽ tìm ra tin nhắn trong console và có thể dùng bất cứ routes nào. References https://medium.freecodecamp.org/going-out-to-eat-and-understanding-the-basics-of-express-js-f034a029fb66