zoukankan      html  css  js  c++  java
  • ReactiveX 学习笔记(25)使用 RxJS + Vue.js 调用 REST API

    JSON : Placeholder

    JSON : Placeholder (https://jsonplaceholder.typicode.com/) 是一个用于测试的 REST API 网站。
    以下使用 RxJS6 + Vue.js 调用该网站的 REST API,获取字符串以及 JSON 数据。

    • GET /posts/1
    • GET /posts
    • POST /posts
    • PUT /posts/1
    • DELETE /posts/1

    所有 GET API 都返回JSON数据,格式(JSON-Schema)如下:

    {
      "type":"object",
      "properties": {
        "userId": {"type" : "integer"},
        "id": {"type" : "integer"},
        "title": {"type" : "string"},
        "body": {"type" : "string"}
      }
    }
    

    创建工程

    # 安装 Vue CLI
    $ npm install --global @vue/cli
    # 创建新的应用程序 RxExample
    $ vue create rx-example
    # 选择 Manually select features
    # 选择 Babel 和 TypeScript
    $ cd rx-example
    $ npm run serve
    

    打开 Intellij IDEA, File / New / Project From Existing Sources...,然后选中工程所在文件夹
    在向导的第1页选择 Create project from existing sources
    完成向导后在点击 Finish 创建工程。

    点击 Add Configurations, 点击 +npm
    Name: Vue CLI Server
    Scripts: serve
    点击 OK 完成配置。
    点击 Vue CLI Server 启动程序。
    http://localhost:8080/ 可打开网页。

    Post

    在 src 文件夹下添加 post.ts,内容如下

    export class Post {
      userId!: number;
      id!: number;
      title!: string;
      body!: string;
      toString(): string {
        return `Post {userId = ${this.userId}, id = ${this.id}, title = "${this.title}", body = "${this.body.replace(/
    /g, '\n')}"}`;
      }
    }
    

    安装 vue-typescript-inject

    vue-typescript-inject 是一个在 Vue.js 中实现 DI(依赖注入) 的包。
    使用这个包需要安装 vue-typescript-inject 和 reflect-metadata。

    $ npm i vue-typescript-inject reflect-metadata
    

    打开 tsconfig.json 在 compilerOptions 中
    添加关于 emitDecoratorMetadata 的设定。

        "emitDecoratorMetadata": true,
        "experimentalDecorators": true,
    

    打开 main.ts 将其改为

    import 'reflect-metadata';
    import Vue from 'vue'
    import App from './App.vue'
    import VueTypeScriptInject from 'vue-typescript-inject';
    
    Vue.config.productionTip = false;
    
    Vue.use(VueTypeScriptInject); // register vue-typescript-inject
    
    
    new Vue({
      render: h => h(App),
    }).$mount('#app');
    

    安装 Rxios

    访问 API 采用将 RxJS 和 axios 合为一体的 Rxios 组件,但是该组件尚未升级到 RxJS6。
    这里我们只安装 RxJS 和 axios,然后直接以源码形式引入 Rxios,并将其升级到 RxJS6。

    $ npm install axios rxjs
    

    在 src 文件夹下添加 rxios.ts,内容如下

    // https://github.com/davguij/rxios/blob/master/src/index.ts
    // ported to rxjs6
    
    import axios, { AxiosInstance, AxiosRequestConfig, AxiosPromise } from 'axios';
    // import { Observable } from 'rxjs/Observable';
    import { Observable } from 'rxjs';
    
    export interface rxiosConfig extends AxiosRequestConfig {
      localCache?: boolean;
    }
    
    class rxios {
      private _httpClient: AxiosInstance;
    
      constructor(options: rxiosConfig = {}) {
        this._httpClient = axios.create(options);
      }
    
      private _makeRequest<T>(method: string, url: string, queryParams?: object, body?: object) {
        let request: AxiosPromise<T>;
        switch (method) {
          case 'GET':
            request = this._httpClient.get<T>(url, {params: queryParams});
            break;
          case 'POST':
            request = this._httpClient.post<T>(url, body, {params: queryParams});
            break;
          case 'PUT':
            request = this._httpClient.put<T>(url, body, {params: queryParams});
            break;
          case 'PATCH':
            request = this._httpClient.patch<T>(url, body, {params: queryParams});
            break;
          case 'DELETE':
            request = this._httpClient.delete(url, {params: queryParams});
            break;
    
          default:
            throw new Error('Method not supported');
        }
        return new Observable<T>(subscriber => {
          request.then(response => {
            subscriber.next(response.data);
            subscriber.complete();
          }).catch((err: Error) => {
            subscriber.error(err);
            subscriber.complete();
          });
        });
      }
    
      public get<T>(url: string, queryParams?: object) {
        return this._makeRequest<T>('GET', url, queryParams);
      }
    
      public post<T>(url: string, body: object, queryParams?: object) {
        return this._makeRequest<T>('POST', url, queryParams, body);
      }
    
      public put<T>(url: string, body: object, queryParams?: object) {
        return this._makeRequest<T>('PUT', url, queryParams, body);
      }
    
      public patch<T>(url: string, body: object, queryParams?: object) {
        return this._makeRequest<T>('PATCH', url, queryParams, body);
      }
    
      public delete(url: string, queryParams?: object) {
        return this._makeRequest('DELETE', url, queryParams);
      }
    }
    
    export {rxios, rxios as Rxios};
    

    post 服务

    在 src 文件夹下添加 post.service.ts,内容如下

    import { Injectable } from 'react.di';
    import { Observable, from } from 'rxjs';
    import { map, mergeAll, take, tap } from 'rxjs/operators';
    import { Post } from './post';
    import { Rxios } from './rxios';
    
    @Injectable
    export class PostService {
      private readonly http = new Rxios();
      private readonly baseUrl = 'http://jsonplaceholder.typicode.com/';
    
      constructor() {
        this.getPostAsString().subscribe();
        this.getPostAsJson().subscribe();
        this.getPosts(2).subscribe();
        this.createPost().subscribe();
        this.updatePost().subscribe();
        this.deletePost().subscribe();
      }
    
      private getPostAsString(): Observable<string> {
        const url = `${this.baseUrl}posts/1`;
        return new Rxios({transformResponse: undefined}).get<string>(url)
          .pipe(
            tap((result: any) => console.log(result)),
          );
      }
    
      private getPostAsJson(): Observable<Post> {
        const url = `${this.baseUrl}posts/1`;
        return this.http.get<Post>(url)
          .pipe(
            map((result: any) => Object.assign(new Post(), result)),
            tap((result: any) => console.log('' + result)),
          );
      }
    
      private getPosts(n: number): Observable<Post> {
        const url = `${this.baseUrl}posts`;
        return from(this.http.get<Post[]>(url))
          .pipe(
            mergeAll(),
            map((result: any) => Object.assign(new Post(), result)),
            take(n),
            tap((result: any) => console.log('' + result)),
          );
      }
    
      private createPost(): Observable<string> {
        const url = `${this.baseUrl}posts`;
        return this.http.post(url, {
          params: {
            userId: 101,
            title: 'test title',
            body: 'test body',
          }
        })
          .pipe(
            map((result: any) => JSON.stringify(result)),
            tap((result: any) => console.log(result)),
          );
      }
    
      private updatePost(): Observable<string> {
        const url = `${this.baseUrl}posts/1`;
        return this.http.put(url, {
          params: {
            userId: 101,
            title: 'test title',
            body: 'test body',
          }
        })
          .pipe(
            map((result: any) => JSON.stringify(result)),
            tap((result: any) => console.log(result)),
          );
      }
    
      private deletePost(): Observable<string> {
        const url = `${this.baseUrl}posts/1`;
        return this.http.delete(url)
          .pipe(
            map((result: any) => JSON.stringify(result)),
            tap((result: any) => console.log(result)),
          );
      }
    }
    
    • getPostAsString 方法取出第1个Post,返回字符串
    • getPostAsJson 方法取出第1个Post,返回Post对象
    • getPosts 方法取出前n个Post,返回n个Post对象
    • createPost 方法创建1个Post,返回字符串
    • updatePost 方法更新第1个Post,返回字符串
    • deletePost 方法删除第1个Post,返回字符串

    删除 HelloWorld 组件,即 src/components/HelloWorld.vue 文件。

    打开 App.vue,将其改为

    <template>
    </template>
     
    <script lang="ts">
    import { Component, Vue } from 'vue-property-decorator';
    import { PostService } from './post.service';
    import { inject } from 'vue-typescript-inject';
     
    @Component({
      providers: [
        PostService,
      ],
    })
    export default class App extends Vue {
      @inject() postService!: PostService;
    }
    </script>
     
    <style>
    </style>
    

    输出结果

    {
      "userId": 1,
      "id": 1,
      "title": "sunt aut facere repellat provident occaecati excepturi optio reprehenderit",
      "body": "quia et suscipit
    suscipit recusandae consequuntur expedita et cum
    reprehenderit molestiae ut ut quas totam
    nostrum rerum est autem sunt rem eveniet architecto"
    }
    Post {userId = 1, id = 1, title = "sunt aut facere repellat provident occaecati excepturi optio reprehenderit", body = "quia et suscipit
    suscipit recusandae consequuntur expedita et cum
    reprehenderit molestiae ut ut quas totam
    nostrum rerum est autem sunt rem eveniet architecto"}
    Post {userId = 1, id = 2, title = "qui est esse", body = "est rerum tempore vitae
    sequi sint nihil reprehenderit dolor beatae ea dolores neque
    fugiat blanditiis voluptate porro vel nihil molestiae ut reiciendis
    qui aperiam non debitis possimus qui neque nisi nulla"}
    Post {userId = 1, id = 1, title = "sunt aut facere repellat provident occaecati excepturi optio reprehenderit", body = "quia et suscipit
    suscipit recusandae consequuntur expedita et cum
    reprehenderit molestiae ut ut quas totam
    nostrum rerum est autem sunt rem eveniet architecto"}
    {"params":{"userId":101,"title":"test title","body":"test body"},"id":101}
    {"params":{"userId":101,"title":"test title","body":"test body"},"id":1}
    {}
    
  • 相关阅读:
    Java使用POS打印机(无驱)
    关于在安装MySQL时报错"本地计算机上的mysql服务启动后停止,某些服务在未由其他服务或程序使用时将自动停止"的解决方法
    Eclipse使用Git教程
    Android studio使用git教程
    数组
    序列化对象
    对象的三个属性
    javascript权威指南笔记--javascript语言核心(六)
    javascript权威指南笔记--javascript语言核心(五)--getter和setter属性
    javascript权威指南笔记--javascript语言核心(四)
  • 原文地址:https://www.cnblogs.com/zwvista/p/9974653.html
Copyright © 2011-2022 走看看