路由處理器
路由處理器讓您定義 Mirage 伺服器可以處理哪些 URL。
最簡單的路由處理器將 URL 對應到一個物件
this.get("/movies", { movies: ["Interstellar", "Inception", "Dunkirk"] })
現在,當您的應用程式向 /movies
發出 GET 請求時,它將收到此物件作為 JSON 資料。
如果您的 API 與應用程式位於不同的主機或埠,請設定 urlPrefix
routes() {
this.urlPrefix = 'https://127.0.0.1:3000';
您也可以透過傳入函數作為第二個引數來編寫函數路由處理器
this.get("/movies", (schema, request) => {
return ["Interstellar", "Inception", "Dunkirk"]
})
函數路由處理器是編寫路由處理器最彈性的方式,因為它們讓您可以存取 Mirage 的資料層和請求物件。您的大部分路由處理器都會是函數。
您可以使用任何 HTTP 動詞來定義您的 API 路由。每個動詞方法都具有相同的簽名。第一個引數是路徑 (URL),第二個引數是傳回回應的函數。
this.get('/movies', () => { ... });
this.post('/movies', () => { ... });
this.patch('/movies/:id', () => { ... });
this.put('/movies/:id', () => { ... });
this.del('/movies/:id', () => { ... });
this.options('/movies', () => { ... });
時間控制
路由處理器的最後一個引數是一個選項物件,您可以使用它來調整時間控制。使用它來延遲特定路由的回應,並查看您的應用程式在與慢速網路通訊時的行為。
this.get(
"/movies",
() => {
return ["Interstellar", "Inception", "Dunkirk"]
},
{ timing: 4000 }
)
開發期間的預設延遲為 400 毫秒,測試期間為 0(因此您的測試執行速度很快)。
您也可以為所有路由設定全域時間參數。個別的時間參數會覆寫全域設定。
createServer({
routes() {
this.namespace = "api"
this.timing = 2000
this.get("/movies", () => {
return ["Interstellar", "Inception", "Dunkirk"]
})
this.get(
"/complex-query",
() => {
return [1, 2, 3, 4, 5]
},
{ timing: 3000 }
)
},
})
如果您想為測試新增延遲,您可以透過將時間參數放在測試中來覆寫個別測試的時間
test("this route works with a delay", function () {
server.timing = 10000
// ...
})
由於伺服器會在每次測試後重設,因此此選項不會洩漏到您其餘的套件中。
存取資料層
路由處理器會接收 schema
作為其第一個參數,這讓它們可以存取 Mirage 的資料層
this.get("/movies", (schema) => {
return schema.movies.all()
})
您的大部分路由處理器都會以某種方式與資料層互動。
第二個參數是 request
物件,其中包含您的應用程式發出之請求的相關資訊。例如,您可以從中存取動態 URL 段
this.get("/movies/:id", (schema, request) => {
let id = request.params.id
return schema.movies.find(id)
})
您也可以存取請求主體,例如處理包含應用程式傳送資料的 POST 或 PATCH 請求
this.post("/movies", (schema, request) => {
let attrs = JSON.parse(request.requestBody)
return schema.movies.create({ attrs })
})
normalizedRequestAttrs
輔助工具(如下所述)提供了一些處理請求資料的簡化方式。
動態路徑與查詢參數
注入到路由處理器的請求物件包含任何動態路由段和查詢參數。
若要定義具有動態段的路由,請在路徑中使用冒號語法 (:segment
)。動態部分將透過 request.params.[segment]
提供
this.get("/authors/:id", (schema, request) => {
let id = request.params.id
return schema.authors.find(id)
})
也可以透過 request.queryParams.[param]
存取請求中的查詢參數。
狀態碼與標頭
預設情況下,Mirage 會根據路由使用的動詞設定回應的 HTTP 狀態碼
- GET 為 200
- PATCH/PUT 為 204
- POST 為 201
- DEL 為 204
如果 PATCH/PUT 和 POST 請求有回應主體,則會將狀態碼變更為 200。
此外,會將 Content-Type
的標頭設定為 application/json
。
您可以在路由處理函式中回傳 Response
類別的實例,來自訂回應碼和標頭。
import { createServer, Model, Response } from "miragejs"
createServer({
models: {
author: Model,
},
routes() {
this.post("/authors", function (schema, request) {
let attrs = JSON.parse(request.requestBody).author
if (attrs.name) {
return schema.authors.create(attrs)
} else {
return new Response(
400,
{ some: "header" },
{ errors: ["name cannot be blank"] }
)
}
})
},
})
外部來源
您可以使用 Mirage 來模擬跨來源請求。預設情況下,像這樣的路由:
this.get('/contacts', ...)
會攔截向伺服您應用程式的相同來源發出的請求。若要處理不同的來源,請使用完整的網域名稱。
this.get('http://api.twitter.com/v1', ...)
如果您的整個應用程式使用外部(跨來源)API,您可以透過 urlPrefix
全域設定網域。
createServer({
routes() {
this.urlPrefix = 'https://my.api.com';
// This route will intercept requests to https://my.api.com/contacts
this.get('/contacts', ...)
}
})
輔助工具
在編寫函式路由處理函式時,有幾個可用的輔助函式。
如果您是 Mirage 的新手,請不用擔心現在就理解這些。當您編寫更進階的路由處理函式時,它們會很有幫助。
serialize
此輔助函式在將指定的 Model 或 Collection 傳遞通過 Serializer 層之後,會回傳其 JSON。如果您想要在回傳序列化 JSON 之前對其進行一些最終處理,這會很有用。
// Note: Be sure to use function() here, rather than () => {}
this.get("/movies", function (schema) {
let movies = schema.movies.all()
let json = this.serialize(movies)
json.meta = { page: 1 }
return json
})
預設情況下,此方法會針對指定的 Model 或 Collection 使用指定的序列化器。您可以傳入特定的序列化器名稱作為第二個引數。
this.get("/movies", function (schema) {
let movies = schema.movies.all()
let json = this.serialize(movies, "sparse-movie")
json.meta = { page: 1 }
return json
})
您將在本指南的稍後章節中學到更多關於序列化器的資訊。
normalizedRequestAttrs
此輔助函式會以標準化形式回傳請求的主體,適用於使用和建立記錄。它本質上會移除 API 酬載中的格式設定邏輯,讓您取得基礎屬性,然後您可以使用這些屬性來修改 Mirage 的資料庫。
例如,如果您的應用程式使用以下資料發出 POST 請求:
// POST /users
{
"data": {
"type": "users",
"attributes": {
"first-name": "Conan",
"middle-name": "the",
"last-name": "Barbarian"
},
"relationships": {
"team": {
"data": {
"type": "teams",
"id": 1
}
}
}
}
}
那麼可以像這樣使用 normalizedRequestAttrs()
:
this.post("/users", function (schema, request) {
let attrs = this.normalizedRequestAttrs()
/*
attrs is this object:
{
firstName: 'Conan',
middleName: 'the',
lastName: 'Barbarian',
teamId: '1'
}
*/
return schema.users.create(attrs)
})
請注意,屬性鍵已轉換為駝峰式大小寫,並且已提取 team
外鍵。這是因為 user
擁有 team
外鍵;如果請求中包含另一個關係,但 user
沒有擁有其外鍵,則不會提取它。
此輔助方法會利用您序列化器的 normalize
方法。在上面的範例中,假設應用程式正在使用 JSONAPISerializer
,它已經附帶了寫好的 #normalize
方法。如果您沒有使用任何綁定的序列化器,則需要實作 #normalize
並使其回傳 JSON:API 文件,才能使用此方法。
此外,您需要在此處使用完整的 function
,而不是 ES6 箭頭函式(例如 () => { ... }
)。這是因為 normalizedRequestAttrs
需要來自函式處理函式的 this
內容,而箭頭函式會從外部範圍繫結 this
。
normalizedRequestAttrs()
依賴 modelName
來運作,並嘗試根據請求的 URL 自動偵測它。如果您使用傳統的 URL(例如,PATCH /users/1),則輔助函式應該可以運作。如果您使用自訂的 URL(例如,PATCH /users/edit/1),則需要將 modelName
作為第一個引數提供給輔助函式。
this.patch("/users/edit/:id", function (schema, request) {
let attrs = this.normalizedRequestAttrs("user")
// ...
})
這就是關於編寫低階函式路由處理函式的所有內容!
函式路由處理函式很靈活,但對於每個端點來說,編寫起來也很繁瑣。如果您正在使用足夠傳統的 API,希望您會編寫較少的函式路由處理函式和更多的簡寫。接下來讓我們討論這些!