Ember.js 中 JSONAPIAdapter 的經常使用 API

Ember JSONAPIAdapter

目前 Emberjs 框架中使用 JSONAPIAdapter 爲默認的 adapter,遵循 JSONAPI 的通訊標準。目前本公司也默認使用的是此 adapter,因此一下 api 均是在此基礎上。
另如無特殊說明,文內的文件結構均是在 Pods 目錄結構下的。

Adapter

在 Ember Data 中,adapter 決定了如何向後端傳遞數據,提供了一些能夠設置的接口,如 格式化請求的URL ,設置請求的header 等。
在Emberjs 項目中,你能夠設置頂層的 application/adapter.js 也能夠在每一個對應的 model(pods文件目錄)的文件中建立針對單個model的adapter:modelName/adapter.js。其中針對單個的 adapter.js的優先權大於 application/adapter.jsgit

URL Conventions

在 Ember Data 中默認使用的 DS.JSONAPIAdapter 中,若是要請求數據,能夠在route.js中:github

//    route.js
    model() {
        return this.get('store').findAll('post');
    }

上面的請求默認發向的 url 爲/posts,也就是 JSONAPIAdapter 會默認爲請求路徑轉換爲複數。ajax

提供了幾個默認的請求:json

Action HTTP Verb URL
Find 1 GET /posts/123
Find All 2 GET /posts
Update 3 PATCH /posts/123
Create 4 POST /posts
Delete 5 DELETE /posts/123

請求過程當中的複數轉換

上文也提到了,在使用 JSONAPIAdapter 過程當中,會進行復數的轉換,包括對 modelName也是,會進行轉換,好比說 咱們請求:後端

model(){
        return this.get('store').findAll('campus');
    }

JSONAPIAdapter 中會發送請求到 /campus 中,而尋找的 modelName 則是campu 這顯然不對,因此咱們須要對特殊字詞進行處理。
在 Ember Data 中使用的是 Ember Inflector 控制的複數轉換。一樣的,咱們也須要對它進行設置(pods目錄下):api

// app/app.js
import  './modules/custom-inflector-rules';
//    app/modules/custom-inflector-rules.js
import Inflector from  'ember-inflector';

const inflector = Inflector.inflector;
 
// Tell the inflector that the plural of "campus" is "campuses"

inflector.irregular('campus', 'campuses');
 
// Modules must have an export, so we just export an empty object here

export  default {};

而後能夠看到 請求發送的地址是/campuses,尋找的 modelName也是 campus,如今變成正常的了,數據也是能夠正常顯示的了。數組

properties

JSONAPIAdapter 提供瞭如下 porperties :緩存

coalesceFindRequests

這有篇文章講的這個屬性的使用。下面是具體的使用:
咱們先來看不設置此屬性的時候:服務器

//    後端返回的數據
'data': {
    'type':  'post',
    'id':  'idPost1',
    'attributes': {
        'title':  'post1',
        'content':  'post content'
    },
    'relationships': {
        'comments': {
            'data': [
                {
                'id':  1,
                'type':  'comment'
                },
                {
                'id':  2,
                'type':  'comment'
                }
            ]
        }
    }
}

這是post數據,當咱們請求 post數據的時候:app

//    route.js
    model() {
        return  this.get('store').findRecord('post', 'idPost1');
    }

這時候能夠看到 Ember Data 向 mirage 發送了兩條請求(須要設置 { async: true }:

GET '/comments/1'
GET '/comments/2'

在將coalesceFindRequests屬性設置爲 true的時候:

//    comment/adapter.js
import DS from  'ember-data';

export  default  DS.JSONAPIAdapter.extend({
    coalesceFindRequests:  true
});

能夠看到如今只發送一條請求:

GET '/comments?filter[id]=1,2

defaultSerializer

defaultSerializer 這個屬性設置使用的 serializer:

// post/adapter.js
import DS from  'ember-data';

export  default  DS.JSONAPIAdapter.extend({
    defaultSerializer: 'person'
});

將使用 person/serializer.js 中的設定對 post進行設定。
須要注意的是此屬性起做用的時候只有在此 model 的serializer.js以及 application/serializer.js不存在的時候起做用(Pods目錄)。

header

HTTP 消息頭容許客戶端和服務器經過 requestresponse傳遞附加信息6。某一些 API 會須要一些請求頭,好比如今項目中使用到的 token,就是在每次進行請求的時候都攜帶這些請求頭數據發送給後端服務。通常不在init()中設置header ,而是將其設爲計算屬性:

//    post/adapter.js
    headers:  computed(function () {
        return {
            'dataType':  'json',
            'contentType':  'application/json',
            'Content-Type':  'application/json',
            'Authorization':  `bearer selfToken`
        };
    })

請求頭就被改變了。
這樣就會在每次請求的時候攜帶本地的 token。

host

自定義主機,默認爲本地做用域。

namespace

顧名思義,定義命名空間的.

//    adapter.js
    namespace: '/api/'

main method

pathForType(type)

格式化請求的路徑:

//    router
    this.get('store').findAll('bjCompany');

若是不在adapter.js 中進行設置,發送的請求是:

GET /bj-companies

也就是默認的轉換爲中劃線以及進行復數化,若是不想進行中劃線的轉換:

//    bj-company/adapter.js
import DS from  'ember-data';
import { camelize } from  '@ember/string';
import { pluralize } from  'ember-inflector';
  
export  default  DS.JSONAPIAdapter.extend({
    pathForType(type) {
        let newType =  pluralize(camelize(type));
        return newType;    // newType: bjCompanies
    }
});

這樣就達到了咱們的目的.

buildURL

對URL 進行格式化,主要是進行復數化,能夠經過複寫 pathForType() 方法來達到重寫 URL 的目的.

Record 相關

JSONAPIAdapter 提供的關於 record 的一些 hook,可讓你複寫這些hook的邏輯來達到本身的目的,可是通常徹底符合 JSONAPI 的數據規範後,這些基本不用重寫.更多關於 Record 的部分請查詢 相關API以及其餘文檔.
這裏列舉出來 JSONAPIAdapter 中涉及 record 的一些 hook:

generateIdForRecord()

用於生成在客戶端生成的 Record 的id.返回的值將分配給 record 的primaryKey.通常不多使用.好比:

//    bj-company/adapter.js
    generateIdForRecord(store, type, inputProperties) {
        return  343;
    }

新建立的 Record 的 id 就會變成 343(這裏只是演示做用).

handleResponse()

返回 ajax 請求的數據或錯誤,若是想修改返回的數據規範或錯誤提示能夠在此處進行修改.
不多使用,視具體項目狀況而使用.

isInvalid()

驗證若是是 422 錯誤,在handleResponse()返回一個 InvalidError() 的實例.

isSuccess()

請求返回成功,相應的status:

(status >=  200  && status <  300) || status ===  304;

shouldBackgroundReloadAll()

store使用此方法來肯定在store.findAll使用緩存的記錄數組解析後,存儲是否應從新加載記錄數組。
默認爲 true .
設爲false 以後,帶來的效果就是在本地兩個頁面同時顯示同一 model 實例,從一頁面跳轉到另外一頁面的時候不會再次請求數據.

//    adapter.js
shouldBackgroundReloadAll(store, snapshotArray) {
  return false;
}

注意 這個方法只有在store 返回緩存數據以後才被調用.也就是當第一次請求數據的時候此方法不會被執行.

This method is only checked by the store when the store is returning a cached record array.

shouldBackgroundReloadRecord()

與上面同理.

shouldReloadAll()

當返回 true 的時候會馬上再次請求數據,若是返回false,會當即使用本地緩存.具體使用實例能夠查看 文檔

shouldReloadRecord()

與上面同理.

sortQueryParams()

對查詢的 參數 進行自定義排列,默認使用的是正序.

urlForCreateRecord()

爲經過 store.createRecord()建立的本地 record 在進行 record.save() 操做的時候構建 相應的 url;
其餘的api 也相似:

總結

JSONAPIAdapter 的相關API 的分析到此結束.

Written by FrankWang.

  1. this.get('store').findRecord('post',1)
  2. this.get('store').findAll('post')
  3. postRecord.save()
  4. this.get('store').createRecord('post').save()
  5. postRecord.destroyRecord()
  6. MDN 中查看
相關文章
相關標籤/搜索