描述 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')
  }),
]

按照相同的原则,为其余端点添加请求处理程序:

¥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:

在本教程中,我们将使用模拟响应来响应被拦截的请求。

¥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 standard Response 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.

¥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.

秘诀

¥Recipes

通过浏览我们的秘诀了解处理请求和响应的其他方法。

¥Learn about other ways to work with requests and responses by browsing our recipes.