Lesson 6: Provider & REST API
Deprecated!
ionic g provider auth
# 產生 providers/auth/auth.ts
Provider: 共用的「資料存取」提供者
web
database
感應器
讀寫各種資料來源
provider
登入頁面
景點列表
溫度顯示
讀寫
ionic start restApp blank
cd restApp
ionic g provider rest
建立rest API範例
import { HttpClient } from '@angular/common/http';
import { Injectable } from '@angular/core';
@Injectable()
export class RestProvider {
constructor(public http: HttpClient) {
console.log('Hello RestProvider Provider');
}
}
providers/rest/rest.ts
預設使用HttpClient元件
(屬於HttpClientModule)
什麼是HttpClient?
為App提供使用瀏覽器HTTP (web) 功能
需修改app.module.ts,引入HttpClientModule
...
import { HttpClientModule } from '@angular/common/http';
@NgModule({
...
imports: [
BrowserModule,
HttpClientModule,
IonicModule.forRoot(MyApp)
],
...
})
export class AppModule {}
修改 app.module.ts
引入HttpClientModule
Consumer
不需停下等待
app端
提出要求
承諾
提供服務
服務端
Consumer
不需停下等待
app端
提出要求
承諾
提供服務
服務端
提供失敗
繼續執行
???
https://angularfirebase.com/images/observable-animation.gif
https://developers.redhat.com/blog/wp-content/uploads/2017/06/reactive-programming.png
時間軸
點擊事件
觸發程式
要求Server回傳資料
回應資料流
更新畫面
https://cdn-images-1.medium.com/max/800/1*q-dcW2ShfaUKxxuzPhS_sQ.png
REST是一種軟體設計風格: Representational State Transfer
以web url(網址)形式呈現各種「資料存取」
符合REST設計風格:Restful API
寫入
讀出
(網址)
網站、Apps
Restful資料存取?
新增(POST)/ 查詢(GET)/ 修改 (PUT) / 刪除 (DELETE) 四大功能
不需參數
需提供參數
無回傳值
有回傳值
新增
// POST adds a random id to the object sent
fetch('https://jsonplaceholder.typicode.com/posts', {
method: 'POST',
body: JSON.stringify({
title: 'foo',
body: 'bar',
userId: 1
}),
headers: {
"Content-type": "application/json; charset=UTF-8"
}
})
.then(response => response.json())
.then(json => console.log(json))
指定Restful網址
body: 所傳遞之內容
格式:JSON
header: 表頭
資料特性,此處說明格式JSON,編碼UTF-8
如何提供參數?設定body, header
回傳結果?JSON格式
JSON
ionic start restApp blank
cd restApp
ionic g provider rest
建立rest API範例
...
import { HttpClientModule } from '@angular/common/http';
@NgModule({
...
imports: [
BrowserModule,
HttpClientModule,
IonicModule.forRoot(MyApp)
],
...
})
export class AppModule {}
修改 app.module.ts
引入HttpClientModule
ionic start restApp blank
cd restApp
ionic g provider rest
建立rest API範例
...
import { HttpClientModule } from '@angular/common/http';
@NgModule({
...
imports: [
BrowserModule,
HttpClientModule,
IonicModule.forRoot(MyApp)
],
...
})
export class AppModule {}
修改 app.module.ts
引入HttpClientModule
修改rest.ts,加入查詢(get)功能
使用免費Rest伺服器:https://jsonplaceholder.typicode.com
查詢使用者的網址為:https://jsonplaceholder.typicode.com/users
引入 Observable
加入查詢功能
...
export class RestProvider {
apiUrl = 'https://jsonplaceholder.typicode.com';
...
}
export class RestProvider {
...
getUsers(): Observable<any>{
return this.http.get(this.apiUrl+'/users');
}
}
import { Observable } from 'rxjs/Observable';
import { HttpClient } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { Observable } from 'rxjs/Observable';
@Injectable()
export class RestProvider {
apiUrl = 'https://jsonplaceholder.typicode.com';
constructor(public http: HttpClient) {
console.log('Hello RestProvider Provider');
}
getUsers(): Observable<any>{
return this.http.get(this.apiUrl+'/users');
}
}
rest.ts
import { Component } from '@angular/core';
import { NavController } from 'ionic-angular';
import { RestProvider } from '../../providers/rest/rest';
@Component({
selector: 'page-home',
templateUrl: 'home.html'
})
export class HomePage {
users: any;
constructor(public navCtrl: NavController, public rest: RestProvider) {
this.rest.getUsers().subscribe(value => {
this.users = value;
console.log(this.users);
});
}
}
HomePage使用getUsers
訂閱getUsers
1. 引入RestProvider
2. 建立RestProvider變數
4. 訂閱getUsers()
3. 建立接收資料用屬性
5. 成功接收資料
home.ts
<ion-header>
<ion-navbar>
<ion-title>
Rest範例
</ion-title>
</ion-navbar>
</ion-header>
<ion-content>
<ion-list inset>
<ion-item *ngFor="let user of users">
<h2>{{user.name}}</h2>
<p>{{user.email}}</p>
</ion-item>
</ion-list>
</ion-content>
home.html
修改rest.ts,加入新增(POST)功能
新增使用者的網址也是:https://jsonplaceholder.typicode.com/users
加入「新增」功能addUser
import { HttpClient, HttpHeaders } from '@angular/common/http';
....
....
export class RestProvider {
apiUrl = 'https://jsonplaceholder.typicode.com';
...
addUser(data): Observable<any>{
return this.http.post(this.apiUrl+'/users', JSON.stringify(data),{
headers: new HttpHeaders().set("Content-type", "application/json; charset=UTF-8")
});
}
}
1. 引入HttpHeaders: 可設定POST訊息的header
3. 將要一併送出的參數data,做成JSON
2. POST: 新增
4. new HttpHeaders().set:視需要設定表頭某個欄位
新增頁面adduser
import { AdduserPageModule } from '../pages/adduser/adduser.module';
...
@NgModule({
...
imports: [
AdduserPageModule,
...
],
...
export class AppModule {}
ionic g page adduser
修改app.module.ts
加入新模組
頁面adduser使用RestProvider
import { RestProvider } from '../../providers/rest/rest';
import { HomePage } from '../home/home';
...
export class AdduserPage {
user = { name: '', username: '', email: '', phone: '', website: '',
address: { street: '', suite: '', city: '', zipcode: '', geo: { lat: '', lng: '' } },
company: { name: '', bs: '', catchPhrase: '' }};
constructor(public navCtrl: NavController, public navParams: NavParams,
public rest: RestProvider) {}
saveUser() {
this.rest.addUser(this.user).subscribe(result => {
console.log('Success:',result);
this.navCtrl.setRoot(HomePage);
}, err => {
console.log('Error',err);
})
}
}
修改adduser.ts
訂閱addUser()
<ion-header>
<ion-navbar>
<ion-title>adduser</ion-title>
</ion-navbar>
</ion-header>
<ion-content padding>
<h2>Add User</h2>
<form (ngSubmit)="saveUser()">
<ion-item>
<ion-label>Name</ion-label>
<ion-input type="text" [(ngModel)]="user.name" name="name"></ion-input>
</ion-item>
<ion-item>
<ion-label>Username</ion-label>
<ion-input type="text" [(ngModel)]="user.username" name="username"></ion-input>
</ion-item>
<ion-item>
<ion-label>Email</ion-label>
<ion-input type="email" [(ngModel)]="user.email" name="email"></ion-input>
</ion-item>
<ion-item>
<ion-label>Phone</ion-label>
<ion-input type="text" [(ngModel)]="user.phone" name="phone"></ion-input>
</ion-item>
<ion-item>
<ion-label>Website</ion-label>
<ion-input type="url" [(ngModel)]="user.website" name="website"></ion-input>
</ion-item>
<ion-item-divider color="light">Address</ion-item-divider>
<ion-item>
<ion-label>Street</ion-label>
<ion-input type="text" [(ngModel)]="user.address.street" name="street"></ion-input>
</ion-item>
<ion-item>
<ion-label>Suite</ion-label>
<ion-input type="text" [(ngModel)]="user.address.suite" name="suite"></ion-input>
</ion-item>
<ion-item>
<ion-label>City</ion-label>
<ion-input type="text" [(ngModel)]="user.address.city" name="city"></ion-input>
</ion-item>
<ion-item>
<ion-label>Zip Code</ion-label>
<ion-input type="text" [(ngModel)]="user.address.zipcode" name="zipcode"></ion-input>
</ion-item>
<ion-item>
<ion-label>Geo</ion-label>
<ion-input type="text" [(ngModel)]="user.address.geo.lat" name="lat" placeholder="Latitude"></ion-input>
<ion-input type="text" [(ngModel)]="user.address.geo.lng" name="lng" placeholder="Longitude"></ion-input>
</ion-item>
<ion-item-divider color="light">Company</ion-item-divider>
<ion-item>
<ion-label>Name</ion-label>
<ion-input type="text" [(ngModel)]="user.company.name" name="name"></ion-input>
</ion-item>
<ion-item>
<ion-label>Business</ion-label>
<ion-input type="text" [(ngModel)]="user.company.bs" name="bs"></ion-input>
</ion-item>
<ion-item>
<ion-label>Catch Phrase</ion-label>
<ion-input type="text" [(ngModel)]="user.company.catchPhrase" name="catchPhrase"></ion-input>
</ion-item>
<button ion-button type="submit" block>Add User</button>
</form>
</ion-content>
adduser.html
表單送出後,返回首頁
並在console印出「成功/錯誤」訊息