
1. Định nghĩa
Routing trong hapi.js giúp server phân loại và xử lý các tác vụ theo yêu cầu được gửi lên từ người dùng. Trong hapi, routing được khai báo như là một thuộc tính của server server.route(...)
.
2. Các thuộc tính cơ bản
Khi định nghĩa một route trong hapi, các bạn cần ba thuộc tính cơ bản: path
, method
và handler
. Các thuộc tính này được khai báo dưới dạng một đối tượng đơn giản như sau:
server.route({ method: 'GET', path: '/', handler: function (request, h) { return 'Hello World!'; } });
# Method
Khi một request được gửi lên server, nó sẽ được gửi theo nhiều phương thức HTTP khác nhau. Để hapi biết cần xử lý request đó ở route nào, chúng ta cần khai báo thuộc tính method trong mỗi route. Method có thể nhận một hoặc nhiều phương thức HTTP hợp lệ.
Ví dụ: Chúng ta muốn trả về cùng một kết quả khi người dùng gửi request lên theo hai phương thức POST
và PUT
như sau:
server.route({ method: ['PUT', 'POST'], path: '/', handler: function (request, h) { return 'I did something!'; } });
# Path
Path là một chuỗi, được hiểu là đường dẫn phía sau domain khi chúng ta nhập vào url của trình duyệt.
Ví dụ: Chúng ta muốn khi truy cập vào url http://localhost/hello
thì sẽ nhận được một chuỗi Hello World!
. Vậy path của route này sẽ là /hello
.
server.route({ method: 'GET', path: '/hello', handler: function (request, h) { return 'Hello World!'; } });
# Parameters
Chúng ta có thể thêm các tham số (parameters) vào route bằng cách đặt tên tham số trong dấu {}.
server.route({ method: 'GET', path: '/hello/{user}', handler: function (request, h) { return 'Hello ' + request.params.user; } });
Với các tham số được truyền vào, nó sẽ được truy vấn qua đối tượng request.params
. Chúng ta có thể định nghĩa nhiều tham số trong một route. Mỗi tham số phải được ngăn cách nhau bởi một ký tự hợp lệ trong url.
/path/{param1}/{param2}
/path/{param1}.{param2}
/path/{param1}-{param2}
# Optional parameters
Để định nghĩa một tham số không bắt buộc, chỉ cần thêm dấu ?
vào cuối tên của tham số. Lúc này, tham số có thể có hoặc không có giá trị.
server.route({ method: 'GET', path: '/hello/{user?}', handler: function (request, h) { const user = request.params.user ? request.params.user : 'stranger'; return `Hello ${user}!`; } });
# Query Parameters
Query parameters là một cách phổ biến để gửi dữ liệu lên server. Các tham số được gửi qua URL dưới dạng key = value
. Ví dụ:
localhost:3000?name=ferris&location=chicago
Trong route của hapi các bạn không cần phải khai báo thêm gì. Toàn bộ các query parameters được truy vấn thông qua đối tượng request.query
.
server.route({ method: 'GET', path: '/', handler: function (request, h) { return `Hello ${request.query.name}!`; } });
# Request Payload
Request payload được hiểu là một khối dữ liệu được truyền lên server thông qua các phương thức ẩn như POST, PATCH hoặc PUT, …
Dữ liệu kiểu này được truy vấn qua đối tượng request.payload
.
server.route({ method: 'POST', path: '/signup', handler: function (request, h) { const payload = request.payload; return `Welcome ${encodeURIComponent(payload.username)}!`; } });
# Handler
Handler là một hàm có nhiệm vụ xử lý và trả về kết quả cho mỗi route. Handler có hai tham số chính là request
và h
. Hàm này có thể trả về một giá trị, một promise hoặc throw một lỗi.
Tham số request
là một đối tượng chứa các thông tin của một request từ người dùng, chẳng hạn như đường dẫn, các dữ liệu payload, thông tin xác thực người dùng, header, v.v. Bạn có thể tham khảo thêm tại đây: https://hapijs.com/api#request
Tham số thứ hai h
là một đối tượng chứa các phương thức bổ sung, hỗ trợ cho việc trả về kết quả của handler. Chúng ta có thể chỉ định các giá trị được trả về như http status code, headers, content type, content length, v.v.
server.route({ method: 'GET', path: '/', handler: function (request, h) { return h.response('created').code(201); } });
Đoạn mã trên sẽ trả về http status code là 201 cho phía người dùng. Tham khảo thêm tại đây: https://hapijs.com/api#response-toolkit
# Options
Ngoài ba thuộc tính cơ bản kể trên, bạn có thể khai báo thêm một thuộc tính options
cho mỗi route. Thuộc tính này bao gồm các cấu hình cho validation, authentication, caching, v.v. Xem thêm tại đây: https://hapijs.com/api#route-options
server.route({ method: 'POST', path: '/signup', handler: function (request, h) { const payload = request.payload; return `Welcome ${encodeURIComponent(payload.username)}!`; }, options: { auth: false, validate: { payload: { username: Joi.string().min(1).max(20), password: Joi.string().min(7) } } } });
Đoạn code trên có hai tùy chọn là auth
và validate
.
auth
dùng để cấu hình xác thực người dùng cho route. Tuy nhiên bạn thấy, route này có nhiệm vụ để đăng ký một tài khoản mới nên không cần có xác thực người dùng, do đó, tùy chọn auth
sẽ là false
.
validate
cho phép bạn đặt các quy tắc để xác thực các thành phần như headers
, params
, payload
và failAction
. Bạn có thể sử dụng thư viện Joi để validate cho payload.
3. Xử lý lỗi 404 đơn giản
Đôi khi sẽ có những người dùng cố gắng hoặc vô tình truy cập vào một đường dẫn không có sẵn. Để thông báo với người dùng rằng họ đang gặp phải lỗi không tìm thấy tài nguyên hoặc không có phương thức nào để xử lý request là trả về một lỗi 404. Trong hapi, cách đơn giản nhất là tạo một route chấp nhận tất cả các method
, tất cả các path
và nằm cuối cùng trong danh sách các route được khai báo.
server.route({ method: '*', path: '/{any*}', handler: function (request, h) { return '404 Error! Page Not Found!'; } });
Bạn có thể dùng dấu *
để gán cho method
, điều này có nghĩa route này đang chấp nhận tất cả các phương thức của request. Sau đó gán chuỗi /{any*}
cho path
, như vậy route này sẽ được thực thi khi không có bất kỳ route nào map với đường dẫn mà người dùng truy cập. Cuối cùng là trả về chuỗi 404 Error! Page Not Found!
tại hàm xử lý handler
.
4. Lời kết
Qua bài viết này, bạn sẽ nắm được các thuộc tính cơ bản, khái quát về cách sử dụng routing trong hapi.js. Hi vọng bạn sẽ thấy thích nó và tiếp tục theo dõi những bài viết tiếp theo trong series về hapi.js. Cảm ơn các bạn đã dành thời gian cho bài viết này!