Skip to content

This issue was moved to a discussion.

You can continue the conversation there. Go to discussion →

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Question: Should we use msw to mock server-side apis based on the request body? #2147

Closed
ellsworthjc opened this issue May 9, 2024 · 1 comment

Comments

@ellsworthjc
Copy link

ellsworthjc commented May 9, 2024

Hello, msw team!

We love msw and we think we should use it for a project. However, this project's setup feels a bit abnormal (maybe an understatement) and we're not sure if msw is the best choice or if we are thinking about this correctly.

To summarize, we are using React on the frontend. We make requests via axios with a body to a single endpoint e.g. site.com/api. A server-side controller then takes over and sends the request to where it needs to go through internal server-side apis. Example:

// request from a component
export function getInfo(params) {
  return axiosInstance({
    method: "POST",
    baseURL: "https://site.com/api/",
    data: {
      action: "GET",
      path: `info${handleQueryParams(params)}`,
    },
  });
}

To mock this with msw, we would intercept the site.com/api endpoint, then inside that handler return some json based on the body of the request.

export const handler = [
  // capture request to site.com/api
  http.post("/api", async ({ request }) => {
    // get request body
    const requestJson = await request.json();

    // get url
    const url = new URL("https://placeholderurl.com/" + requestJson.path);

    // get response from responseMap using pathname as the key
    const response = responseMap[url.pathname];

    // return response data
    return HttpResponse.json(response);
  }),
];

responseMap would be a map of the paths to the response data.

export const responseMap = {
  "/info": {
    name: "John Doe",
    email: "[email protected]",
  },
};

This "works" but I guess I'd just like to check with the professionals to see that there isn't a better way. This convoluted mess is probably just because of our backend setup and lack of a true RESTful api for us to access on the frontend.

Thank you in advance for any help and insight that you are willing to give! 🙇

Edit: It's probably better to send another request from the site.com/api handler to another msw intercepted endpoint /info. The original method would not support different request methods for the same endpoints.

@kettanaito
Copy link
Member

Hi, @ellsworthjc. Thank you for your kinds words!

You can choose whichever setup makes sense in the context of your request client, so what you've showcased makes sense if the request body contains the predicate as to how to handle the outgoing requests.

That being said, I feel you can take advantage of MSW's built-in routing if you unfold the requests. Let me show you how.

export const handler = [
  // This is a generic handler that captures the
  // immediate requests your app makes and "unfolds" them.
  http.post('/api', async ({ request }) => {
    const requestJson = await request.json()
    const url = new URL('https://placeholder.com/' + requestJson.path)
    const proxiedRequest = new Request(url, { method: requestJson.action })

    // Instead of looking up the response from a map,
    // perform that request immediately. This will make this
    // proxied request to "fall through" other existing handlers,
    // and whatever mocked response they return will be used here.
    return fetch(proxiedRequest)
  }),

  // Now, describe individual operations to the proxied endpoint.
  // This is a much nicer way to provide method + path matching.
  http.get('https://placeholder.com/info/foo', () => {
    return HttpResponse.json({ ok: true })
  }),
  http.post('https://placeholder.com/info/bar', async ({ request }) => {
    const data = await request.json()
    return HttpResponse.json(data, { status: 201 })
  }),
]

I recommend going with something like this as it gives you more power over request matching while also allowing you to benefit from other MSW features like delays, one-time handlers, etc.

Let me know if you have any other questions!

@kettanaito kettanaito transferred this issue from mswjs/examples May 11, 2024
@mswjs mswjs locked and limited conversation to collaborators May 11, 2024
@kettanaito kettanaito converted this issue into discussion #2148 May 11, 2024

This issue was moved to a discussion.

You can continue the conversation there. Go to discussion →

Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants