Ionic Tutorial

Lesson 6: Provider & REST API

Deprecated!

Outline

  • 啟動HTTP服務模組
  • Promise
  • RxJS Observable

建立Provider

ionic g provider auth
# 產生 providers/auth/auth.ts

Provider: 共用的「資料存取」提供者

web

database

感應器

讀寫各種資料來源

provider

登入頁面

景點列表

溫度顯示

讀寫

建立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)

 

建立Provider

什麼是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
 

非同步執行:Promise

  • 什麼是Promise?

什麼是Promise? (1/2)

Consumer

不需停下等待

app端

提出要求

承諾

提供服務

服務端

什麼是Promise? (2/2)

Consumer

不需停下等待

app端

提出要求

承諾

提供服務

服務端

提供失敗

繼續執行

???

RxJS Observable

  • 處理「非同步資料流」

RxJS ?

  • 處理「非同步」資料流

https://angularfirebase.com/images/observable-animation.gif

https://developers.redhat.com/blog/wp-content/uploads/2017/06/reactive-programming.png

  • 建立Observable
  • 訂閱(Subscription)
  • 激發(Emit)
  • 處理運算子(operators)

時間軸

點擊事件

觸發程式

要求Server回傳資料

回應資料流

更新畫面

RxJS ?

  • 處理「非同步」資料流

https://cdn-images-1.medium.com/max/800/1*q-dcW2ShfaUKxxuzPhS_sQ.png

  • 建立Observable
  • 訂閱(Subscription)
  • 激發(Emit)
  • 處理運算子(operators)

Rest API範例

  • 什麼是REST API?
  • 延續restApp範例
  • provider建立存取功能
  • HomePage呼叫provider存取功能

什麼是REST API?

REST是一種軟體設計風格: Representational State Transfer

        以web url(網址)形式呈現各種「資料存取」

        符合REST設計風格:Restful API

寫入

讀出

(網址)

網站、Apps

什麼是REST API?

Restful資料存取?

          新增(POST)/ 查詢(GET)/ 修改 (PUT) / 刪除 (DELETE)   四大功能

不需參數

需提供參數

無回傳值

有回傳值

什麼是REST API?

新增

// 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

什麼是REST API?

回傳結果?JSON格式

JSON

延續restApp範例

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
 

延續restApp範例

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
 

延續restApp範例查詢(get)

修改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';

延續restApp範例查詢(get)

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

延續restApp範例查詢(get)

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

延續restApp範例查詢(get)

<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

延續restApp範例查詢(get)

延續restApp範例新增(POST)

修改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:視需要設定表頭某個欄位

延續restApp範例新增(POST)

新增頁面adduser

import { AdduserPageModule } from '../pages/adduser/adduser.module';
...
@NgModule({
  ...
  imports: [
    AdduserPageModule,
    ...
  ],
...
export class AppModule {}
ionic g page adduser

修改app.module.ts

加入新模組

延續restApp範例新增(POST)

頁面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()

延續restApp範例新增(POST)

<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

延續restApp範例新增(POST)

表單送出後,返回首頁

並在console印出「成功/錯誤」訊息