描述 REST API
了解如何使用 Mock Service Worker 描述 REST API。
导入
¥Import
MSW 提供指定的 http
命名空间来描述 HTTP 请求。我们将使用该命名空间来描述要拦截的请求以及如何响应它们。
¥MSW provides a designated http
namespace for describing HTTP requests. We will use that namespace to describe what requests to intercept and how to respond to them.
Import the http
namespace from the msw
package:
// src/mocks/handlers.js
import { http } from 'msw'
export const handlers = []
虽然 GraphQL 通常通过 HTTP 实现,但我们强烈建议为 描述 GraphQL API 使用指定的
graphql
命名空间。¥Although GraphQL is often implemented over HTTP, we highly recommend using the designated
graphql
namespace for describing GraphQL APIs.
请求处理程序
¥Request handler
接下来,我们将创建一个 请求处理程序。http
命名空间中的每个方法都允许我们创建与 HTTP 请求方法相对应的请求处理程序:
¥Next, we will create a Request handler. Every method in the http
namespace allows us to create a request handler corresponding to an HTTP request method:
http[method](predicate, resolver)
¥Request handlers are functions that allow you to Intercept requests and Mock responses.
在本教程中,我们将描述一个具有以下端点的基本 RESTful API:
¥In this tutorial, we will describe a basic RESTful API that has the following endpoints:
-
GET /posts
,返回所有现有帖子;¥
GET /posts
, to return all existing posts; -
POST /posts
,创建新帖子;¥
POST /posts
, to create a new post; -
DELETE /posts/:id
,按 ID 删除帖子。¥
DELETE /posts/:id
, to delete a post by ID.
让我们从为 GET /posts
请求创建一个请求处理程序开始。
¥Let’s start by creating a request handler for the GET /posts
requests.
Call http.get()
to declare your first request handler
// src/mocks/handlers.js
import { http } from 'msw'
export const handlers = [
// By calling "http.get()" we're instructing MSW
// to capture all outgoing "GET /posts" requests
// and execute the given response resolver when they
// happen.
http.get('/posts', () => {
// Response resolver allows you to react to captured requests,
// respond with mock responses or passthrough requests entirely.
// For now, let's just print a message to the console.
console.log('Captured a "GET /posts" request')
}),
]
请注意,你还可以提供绝对请求 URL 来拦截对外部服务(如 http.get('https://example.com/resource')
)的请求。
¥Note that you can also provide an absolute request URL to intercept requests
to external services, like http.get('https://example.com/resource')
.
按照相同的原则,为其余端点添加请求处理程序:
¥Following the same principle, add request handlers for the remaining endpoints:
// src/mocks/handlers.js
import { http } from 'msw'
export const handlers = [
http.get('/posts', () => {
console.log('Captured a "GET /posts" request')
}),
http.post('/posts', () => {
console.log('Captured a "POST /posts" request')
}),
http.delete('/posts/:id', ({ params }) => {
console.log(`Captured a "DELETE /posts/${params.id}" request`)
}),
]
定义这些处理程序后,MSW 将拦截相应的请求,但暂时不会对它们做出任何响应。
¥With these handlers defined, MSW will intercept the respective requests but won’t do anything to respond to them just yet.
响应解析器
¥Response resolver
响应解析器是请求处理程序的第二个参数,它决定如何处理被拦截的请求。你可以使用这样的请求执行多种操作:使用模拟响应进行响应、按原样执行、执行代理请求并增强原始响应等。你始终可以在此页面上了解有关响应解析器的更多信息:
¥Response resolver is the second argument to the request handler that decides how to handle the intercepted request. There are multiple things you can do with such a request: respond with a mock response, perform it as-is, perform a proxy request and augment the original response, etc. You can always learn more about response resolver on this pages:
Response resolver
Learn more about response resolvers.
Mocking responses
Learn how to mock HTTP responses.
在本教程中,我们将使用模拟响应来响应被拦截的请求。
¥In this tutorial, we will be responding to the intercepted requests with mock responses.
模拟响应
¥Mocking responses
要响应被拦截的请求,请构造一个有效的 Fetch API Response
实例并从相应的请求处理程序返回它。尽管你可以直接使用 Response
实例,但我们强烈建议你使用库提供的 HttpResponse
类。
¥To respond to an intercepted request, construct a valid Fetch API Response
instance and return it from the corresponding request handler. Although you can work with the Response
instance directly, we highly recommend using the HttpResponse
class provided by the library.
Import the HttpResponse
class from msw
:
import { http, HttpResponse } from 'msw'
了解什么是
HttpResponse
,以及为什么应该在 此处 中使用它而不是标准Response
。¥Learn about what
HttpResponse
is and why you should use it over the standardResponse
in here.
接下来,让我们构造模拟响应以返回所有帖子的列表。
¥Next, let’s construct the mocked response to return the list of all posts.
Return a mocked HttpResponse
from the GET /posts
resolver:
// src/mocks/handlers.js
import { http, HttpResponse } from 'msw'
// Let's keep a map of all existing posts in memory.
// At the beginning, this list is empty as we have no posts.
const allPosts = new Map()
export const handlers = [
http.get('/posts', () => {
// Construct a JSON response with the list of all posts
// as the response body.
return HttpResponse.json(Array.from(allPosts.values()))
}),
// ...the other request handlers.
]
使用 HttpResponse.json()
静态方法,我们将从此解析器返回 application/json
响应以用作模拟响应。
¥Using the HttpResponse.json()
static method, we are returning an application/json
response from this resolver to be used as the mocked response.
读取请求正文
¥Reading request body
在 POST /posts
处理程序中,让我们读取请求主体并将新帖子推送到 allPosts
映射。我们可以将对拦截请求实例的引用作为响应解析器函数的 request
参数获取。
¥In the POST /posts
handler, let’s read the request body and push the new post to the allPosts
map. We can get the reference to the intercepted request instance as the request
argument to the response resolver function.
Read the request body using the request
argument:
// src/mocks/handlers.js
import { http, HttpResponse } from 'msw'
const allPosts = new Map()
export const handlers = [
http.post('/posts', async ({ request }) => {
// Read the intercepted request body as JSON.
const newPost = await request.json()
// Push the new post to the map of all posts.
allPosts.set(newPost.id, newPost)
// Don't forget to declare a semantic "201 Created"
// response and send back the newly created post!
return HttpResponse.json(newPost, { status: 201 })
}),
]
读取路径参数
¥Reading path parameters
最后,让我们实现 DELETE /posts/:id
解析器,它将通过其 ID 从 allPosts
查找和删除帖子。请求 URL 的路径参数被解析并存储为响应解析器函数的 params
参数。
¥Lastly, let’s implement the DELETE /posts/:id
resolver that will lookup and delete a post from allPosts
by its ID. The path parameters of the request URL are parsed and stored as the params
argument to the response resolver function.
Read the id
path parameter using the params
argument
// src/mocks/handlers.js
import { http, HttpResponse } from 'msw'
const allPosts = new Map()
export const handlers = [
http.delete('/posts/:id', ({ params }) => {
// All request path params are provided in the "params"
// argument of the response resolver.
const { id } = params
// Let's attempt to grab the post by its ID.
const deletedPost = allPosts.get(id)
// Respond with a "404 Not Found" response if the given
// post ID does not exist.
if (!deletedPost) {
return new HttpResponse(null, { status: 404 })
}
// Delete the post from the "allPosts" map.
allPosts.delete(id)
// Respond with a "200 OK" response and the deleted post.
return HttpResponse.json(deletedPost)
}),
]
响应解析器为你提供有关被拦截请求的更多有用数据,例如请求 cookie、GraphQL 查询和变量等。了解有关 响应解析器 的更多信息以释放其全部潜力。
¥Response resolver provide you with much more useful data about the intercepted request, such as request cookies, GraphQL query and variables, and more. Learn more about the Response resolvers to unlock their full potential.
读取请求 cookie
¥Reading request cookies
访问请求的 Cookie
标头的解析值作为响应解析器对象参数上的 cookies
键:
¥Access the parsed value of the request’s Cookie
header as the cookies
key on the response resolver object argument:
http.get('/user', ({ cookies }) => {
const { session } = cookies
if (!session) {
return new HttpResponse(null, { status: 401 })
}
})
后续步骤
¥Next steps
集成
¥Integrations
描述所需的网络后,将其集成到应用中的任何环境中。
¥Once you have described the network you want, integrate it into any environment in your application.
Browser
Integrate MSW in a browser environment, such as a React application or Storybook.
Node.js
Integrate MSW in Node.js, such as an Express application or a test runner.
秘诀
¥Recipes
通过浏览我们的秘诀了解处理请求和响应的其他方法。
¥Learn about other ways to work with requests and responses by browsing our recipes.