Service trong AngularJS và các service giao tiếp với máy chủ
- 23-04-2022
- Toanngo92
- 0 Comments
Khái niệm Service trong AngularJS là các hàm để thực thi các tác vụ cụ thể nào đó, giúp cá nhân hóa các thực thể, code dễ dàng maintain và test, services đóng một vai trò rất quan trọng trong các ứng dụng được viết bằng AngularJS, hiện có những service có sẵn mà Angular đã cung cấp cho chúng ta, tuy nhiên chúng ta hoàn toàn có thể mở rộng thêm bằng cách tạo một Service mới. Dưới đây là danh sách một số các Services builtin trong AngularJS:
$anchorScroll
$animate
$cacheFactory
$compile
$controller
$document
$exceptionHandler
$filter
$http
$httpBackend
$interpolate
$interval
$locale
$location
$log
$parse
$q
$rootElement
$rootScope
$sce
$sceDelegate
$templateCache
$templateRequest
$timeout
$window
$event
Mục lục
Giới thiệu một số services phổ biến hay sử dụng
$scope và $rootscope
Xem thêm tại bài viết scope trong AngularJS
$window
Tương tự đối tượng window trong javascript thuần.
$event
Tương tự đối tượng event trong javascript thuần, sử dụng để bắt sự kiện
$location
Biểu diễn url hiện tại của trình duyệt tương tự đối tượng location trong javascript thuần
$http
Để sử dụng service $http này, chúng ta cần hiểu về kiến trúc REST API, bạn có thể xem thêm tại bài viết Services communicate và khái niệm REST API để có thêm kiến thức trước khi bắt đầu.
Docs: https://docs.angularjs.org/api/ng/service/$http
$http trong angularJS là một service (nghiệp vụ) trong angularJS để giao tiếp với server thông qua phương thức .get(), .post() để lấy dữ liệu hoặc gửi dữ liệu thông qua Ajax(), dữ liệu mesage trả về dưới dạng JSON, cơ chế này là cơ chế không đồng bộ (asynchronous), javascript gửi một request lên phía server mã nguồn tiếp tục chạy mà không chờ phản hồi, khi server gửi dữ liệu về trình duyệt bắt dữ liệu trả về và tiếp tục thực thi mã nguồn lập trình viên đã định nghĩa để làm việc với dữ liệu trả về như phân tách dữ liệu, cập nhật HTML … Các phương thức cơ bản REST API như GET,POST,PUT,DELETE đều được định nghĩa sẵn trong service $http.
Cú pháp:
$http({
method: 'GET',
url: '/endpoint',
headers: {
'Content-Type': 'application/json',
Authorization: 'Bearer APIKEY'
} // optional
})
.then(
function (success) {
// do something when success
},
function (error) {
// do something when error
}
);
ngoài ra chúng ta còn có shortcut cho 2 phương thức, giúp cú pháp trở nên ngắn gọn hơn, chúng ta có thể chọn phương thức phù hợp với mình để áp dụng.
app.run(function($http) {
$http.defaults.headers.common['Authorization'] = 'Basic APIKEY';
}); // optinal config header
$http.get('/someUrl', config).then(successCallback, errorCallback);
$http.post('/someUrl', data, config).then(successCallback, errorCallback);
$http service là một hàm, nhận vào 1 tham số, tham số này chính là object (đối tượng) cấu hình cho request, đối tượng này xác định trạng thái cho phương thức HTTP, đường dẫn url, cấu hình header cho method nếu có, hoặc có thể cấu hình body nếu phương thức là POST …
Đối tượng khi một http request gửi đi hoặc trả về có cấu trúc như sau:
- data: là dữ liệu được phản hồi về từ phía server theo một tiêu chuẩn, có thể là chuỗi, hoặc văn bản
- status: HTTP status code
- headers: tham chiếu tới thông tin header
- config: tham chiếu tới đối tượng cấu hình một http request
Khi một phương thức HTTP method được gọi, đối tượng trả về người ta gọi là khái niệm promise object (lời hứa), đối tượng này chứa phương thức chuẩn là .then(), ý nghĩa là sau khi tin hiệu trả về thành công, làm công việc gì đó, và bắt tình huống khi xử lý khi thành công hay gặp lỗi, tham số trong hàm then() là 2 hàm callback với parameter là một biến success, sẽ lưu trữ đối tượng khi tín request thành công, biến error lưu trữ đối tượng khi request gặp lỗi. Ý nghĩa có thể hiểu là nếu thành công, sẽ làm gì đó với dữ liệu trả về trong biến success, tương tự với biến error khi gặp lỗi.
Dưới đây là ví dụ sử dụng phương thức get() của service $http để giao tiếp với server
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Exmample Http method</title>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.8.2/angular.min.js"></script>
</head>
<body>
<div ng-app="myApp">
<div ng-controller="listUserController">
<table>
<tr>
<th>Username</th>
<th>Name</th>
<th>Email</th>
</tr>
<tr ng-repeat="user in users">
<td>{{user.fields.username}}</td>
<td>{{user.fields.fullname}}</td>
<td>{{user.fields.phonenumber}}</td>
</tr>
</table>
</div>
</div>
</body>
<script>
var app = angular.module('myApp', []);
// app.run(function($http) {
// $http.defaults.headers.common['Authorization'] = 'Basic keyMhcG4dscdHl3Nf';
// });
app.controller('listUserController', function ($scope, $http) {
$scope.listUser = [];
$scope.getListUser = $http({
url: "https://urlservcer",
method: 'GET',
headers: {
'Content-Type': 'application/json',
Authorization: 'Bearer APIKEY'
}
}).then(
function (data) {
$scope.users = data.data.records;
},
function (error) {
console.log(error);
alert("get list Failed");
});
// $scope.getListUser();
});
</script>
</html>
Xét ví dụ phía trên, mình đang gửi một phương thức get lên máy chủ thông qua service $http, dữ liệu sau khi lấy về được trả ra thông qua phương thức .then(), phương thức này có 2 tham số truyền vào là một hàm khác, tham số thứ nhất là hàm được gọi lại (callback function) khi gửi request thành công (200), tham số thứ hai là hàm được gọi khi request báo lỗi.
Phát triển thêm, chúng ta có thể thực hiện các tính năng CRUD hiển thị danh sách người dùng, thêm người dùng mới ở phía máy chủ bằng cách kết hợp các phương thức get và post
$resource
Docs: https://docs.angularjs.org/api/ngResource/service/$resource
$resource service trong angularJS cho phép chúng ta có thể truy cập vào ứng dụng REST, tương tự $http nhưng quy chuẩn dữ liệu cần đáp ứng chuẩn JSON, tuân thủ đúng cấu trúc, ý nghĩa là $resource nhận về dữ liệu từ endpoint,dữ liệu có chuẩn hóa riêng tương tác với dữ liệu rồi gửi lại, khá hữu dụng cho việc phát triển các ứng dụng CRUD. Nếu so sánh thì $http sẽ tương tác được với server đa dạng hơn $resource, nhưng với $resource, nếu dữ liệu tầng server đã được chuẩn hóa thì thao tác sẽ nhanh hơn
Ví dụ ứng dụng $resource
Bước 1: tạo file index.html trong thư mục resource
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Example resourece</title>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.8.2/angular.min.js"></script>
<!-- <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.32/angular.js"></script> -->
<script src="https://code.angularjs.org/1.2.32/angular-resource.js"></script>
</head>
<body>
<div ng-app="myApp">
<div ng-controller="listUserController">
<table>
<tr>
<th>Username</th>
<th>Name</th>
<th>Email</th>
</tr>
<tr ng-repeat="user in users">
<td>{{user.fields.username}}</td>
<td>{{user.fields.fullname}}</td>
<td>{{user.fields.phonenumber}}</td>
</tr>
</table>
</div>
</div>
</body>
<script>
var app = angular.module('myApp', ['ngResource']);
// app.run(function($http) {
// $http.defaults.headers.common['Authorization'] = 'Bearer keyMhcG4dscdHl3Nf';
// });
app.controller('listUserController', function ($scope, $resource) {
$scope.users = [];
$scope.getListUsers = $resource('http://localhost/resource/listuser.json').query(function(){
$scope.users = $scope.getListUsers;
});
// console.log( $scope.getListUsers);
});
</script>
</html>
Bước 2: tạo file listuser.json cùng cấp với file index với cấu trúc json mảng các đối tượng:
[
{
"id": "recFrt8MNiEg4jInj",
"createdTime": "2022-04-22T09:19:18.000Z",
"fields": {
"password": "1234567",
"phonenumber": "0911222333",
"username": "toan1234",
"fullname": "username 3"
}
},
{
"id": "recT2YNM75XbD4E4T",
"createdTime": "2022-04-27T13:15:49.000Z",
"fields": {
"phonenumber": "0932159215",
"username": "to9an1134",
"fullname": "Toan ngo vinh"
}
},
{
"id": "recaE9soCIeZgyhVP",
"createdTime": "2022-04-22T09:19:18.000Z",
"fields": {
"password": "1234567",
"phonenumber": "0932321592",
"username": "toanngo92",
"fullname": "toan ngo"
}
},
{
"id": "rectJwBmOAsWDWHnw",
"createdTime": "2022-04-28T01:03:47.000Z",
"fields": {
"phonenumber": "0932159215",
"username": "to9an1134",
"fullname": "Toan ngo vinh"
}
},
{
"id": "recvDBMvANFv5UiK8",
"createdTime": "2022-04-22T09:19:18.000Z",
"fields": {
"password": "1234567",
"phonenumber": "0782222567",
"username": "toan123",
"fullname": "username 2"
}
}
]
Khác biệt giữa $http và $resource khi truy cập thông qua REST API
$http service cơ chế xử lý thông qua AJAX, và hầu hết các lập trình viên sẽ sử dụng trong các trờờng hợp, thông qua nghiệp vụ này, lập trình viên sẽ tạo các GET,POST,DELETE … và xử lý các đối tượng trả về, tuy nhiên lại ít được ứng dụng trong dự án thực tế hơn, có lẽ lí do vì cấu trúc phức tạp, ít code mẫu, dữ liệu trả về không phải là promise nên khó tiếp cận hơn cho người mới.
Trong kịch bản RESTful, $resource ôm $http, nghĩa là với RESTful web service, $resource là option sử dụng. Với $http, chúng ta có thể gửi request tới máy chủ với các cấu trúc khác, ví dụ gửi request tới một website không tuân theo cấu trúc dữ liệu của API và nhận dữ liệu trả về là toàn bộ nội dung html trả ra từ request. Còn với $resource tuân thủ cấu trúc của RESTful.
Restangular
Docs:
Một service có thể truy cập vào REST services là Restangular, đây là một thư viện thứ ba được đưa vào dự án thông qua dependency injection. Nó giúp đơn giản hóa các HTTP Request bằng cách giảm khối lượng code cần viết, có thể sử dụng để làm ứng dụng tương tác RESTful API thay thế cho $http mặc định của angularJS, tất nhiên các phương tư mặc định đều có đầy đủ
Điểm mạnh của Restangular:
- Hỗ trợ tất cả phương thức HTTP
- Không cần phải viết lại URL nhiều lần, chỉ cần định nghĩa endpoint cho resources một lần, các lần tiếp theo sẽ dựa theo cấu trúc endpoint để giao tiếp
- Cho phép cấu hình phương thức tùy chỉnh
Ví dụ khi thực hiện phương thức GET với Restangular:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Exmample Http method</title>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.32/angular.js"></script>
<!-- bat buoc phai load lodash truoc khi load restangular -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.21/lodash.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/restangular@1.6.1/src/restangular.js"></script>
</head>
<body>
<div ng-app="myApp">
<div ng-controller="listUserController">
<table>
<tr>
<th>Username</th>
<th>Name</th>
<th>Email</th>
</tr>
<tr ng-repeat="user in users">
<td>{{user.fields.username}}</td>
<td>{{user.fields.fullname}}</td>
<td>{{user.fields.phonenumber}}</td>
</tr>
</table>
</div>
</div>
</body>
<script>
var app = angular.module('myApp', ['restangular']);
app.config(function (RestangularProvider) {
RestangularProvider.setBaseUrl('https://api.airtable.com/v0/apppcdfKQ5q5rch7A');
RestangularProvider.setDefaultHeaders({
'Content-Type': 'application/json',
Authorization: 'Bearer APIKEY'
});
});
app.controller('listUserController', function ($scope, Restangular) {
$scope.users = [];
$scope.getListUsers = Restangular.all('user').doGET().then(function (result) {
$scope.users = result.records;
console.log($scope.users);
});
console.log($scope.getListUsers);
});
</script>
</html>
Xử lý lỗi khi giao tiếp client-server
Việc xử lý lỗi và ghi log ngoại lệ rất quan trọng trong việc giao tiếp, vì trong thực tế, có rất nhiều tình huống xảy ra, chẳng hạn đường truyền có vấn đề, hạ tầng server lỗi, CSDL găp trục trắc ….
Chúng ta sử dụng các khối try, catch, finally để bắt các ngoại lệ này. Trong angularJS, có cách giúp tiết kiệm thời gian hơn vì có service $exceptionHandle sử dụng để bắt các lỗi ngoại lệ (exception) và không ảnh hưởng tới lộ trình chạy của ứng dụng , vì các lỗi này thường không liên quan tới cú pháp
Ví dụ exception trong angularJS:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Exmample Http method</title>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.32/angular.js"></script>
</head>
<body>
<div ng-app="myApp">
<div ng-controller="listUserController">
<table>
<tr>
<th>Username</th>
<th>Name</th>
<th>Email</th>
</tr>
<tr ng-repeat="user in users">
<td>{{user.fields.username}}</td>
<td>{{user.fields.fullname}}</td>
<td>{{user.fields.phonenumber}}</td>
</tr>
</table>
</div>
</div>
</body>
<script>
var app = angular.module('myApp', []);
app.config(function($provide){
$provide.decorator('$exceptionHandler',function($delegate){
return function (exception,cause){
console.log(exception,cause);
$delegate($exception,cause);
}
});
});
app.controller('listUserController', function ($scope, $http) {
$scope.users = [];
$http({
url: "https://api.airtable.com/v0/apppcdfKQ5q5rch7A/user",
method: 'GET',
headers: {
'Content-Type': 'application/json',
Authorization: 'Bearer APIKEY'
}
}).then(
function (data) {
console.log(data);
$scope.users = data.data.records;
console.log($scope.users);
},
function (error) {
console.log(error);
alert("get list Failed");
});
// $scope.getListUser();
});
</script>
</html>