Is your feature request related to a problem? Please describe.
When using msw within the browser (either storybook or my app), I would like to add a delay to all the responses to get a more realistic behavior.
In tests, I would like the delay to be minimal, as it currently is.
Describe the solution you'd like
One solution would be to support a default delay option when starting a worker:
worker.start({
delay: 1000,
})
I can then configure the delay to be different for different environments.
I'm not sure how this would interact with ctx.delay, would they both be honored or would one override the other?
Describe alternatives you've considered
I could add ctx.delay to every handler, but this feels like a lot of boilerplate for something I want applied to all handlers.
I tried adding a handler to catch all requests and add a delay, but the requests didn't fall to the next handler as I expected. This might be related to https://github.com/mswjs/msw/issues/258.
Hey, @danielstreit. Thanks for raising this.
While we haven't considered providing implicit delay for all requests, there are two things I can recommend:
ctx.delay()Use ctx.delay() without any arguments on a specific response to get a realistic server response delay. This, as you've pointed out, may quickly get repetitive, if you need this for all request handlers.
Abstract implicit delay into your own response composition function. We are striving towards composable functional API, so you can create your own res() function that always uses ctx.delay() and use it for your handlers:
// mocks/utils.js
import { response, context } from 'msw'
export function res(...transformers) {
// Incorporate response delay into the composition itself:
return response(context.delay(), ...transformers)
}
// mocks/handlers.js
import { rest } from 'msw'
import { res } from './utils'
rest.get('/user', (req, _, ctx) => {
// Has implicit delay, because you're using your custom `res` function.
return res(ctx.json({ firstName: 'John' })
})
We encourage to modify and extend the default functionality through composition, rather than adding new options. Developers would often need something specific to their setup, so providing them with the "building blocks" that can use to get the expected behavior in mocks is an optimal strategy.
We have to discuss whether some global delay/other settings should be supported in the native API. Let me know if the suggestions above are helpful.
I don't know if it should be a feature. I think that @kettanaito suggestion is already a good way.
delay() was a very useful feature and it's enough to do everything.
@danielstreit Do you have other use cases that cannot be covered with this suggestion?
Yeah, @kettanaito's suggestion works, I'll got with that.
I'd still consider the ability to handle this as an option in the worker/server API as a nice to have because I think it would reduce the indirection in the code.
But, the proposed solution works well and I'm happy to close this.
Thanks for the help!
Glad to hear it helped!
I'd like to move the library's API towards composition, as in extending it horizontally, rather than going in-depth (if that makes sense). Promoting and encouraging developers to build their own context utility functions, and response resolvers, including the use case you've suggested. Functional composition brings much more power on the end side, and is more sustainable towards breaking changes, IMO. That being said, we are always happy to hear API suggestions, as the library is still evolving and shaping up.
Just a suggestion, we can leave the issue open waiting for thumb up/down.
We can understand what other users want
I don't mind. Let's leave it open and see how the users react. Good idea, @marcosvega91.
I got here looking for the suggested change to the api as I would have thought it would be something standard but after seeing the solution above I would vote not to add it to the API and simply add the solution above to the documentation somewhere. It serves its purpose and is more educational than creating an global .delay()
Hey, @garhbod. There's actually the very same usage example in the recently updated docs already: in the Custom response composition section. It illustrates how you can create your own res function that has a random realistic response delay baked in. I find this more educational and practical as well, and see little reason to extend public API for this purpose.
Maybe it could also be added as a Recipe? Or a note added at the bottom of the response > properties table guiding the user to the composition example if they wish to set "global" context
@garhbod, please, feel free to issue a pull request to the documentation repository with such recipe. I'd gladly help with the review. It would be great to come up with a different practical example of a custom response resolver (i.e. a different build-in context).
The official recommendation is to prefer custom response resolver function if you wish to embed a delay, or other options, present on all responses. This would align well with the library and generally scales much better than extending the public API.
// src/mocks/res.js
import { response, context } from 'msw'
export function res(...transformers) {
// A custom response composition chain that embeds
// a random realistic server response delay to each `res()` call.
return response(...transformers, context.delay())
}
// src/mocks/handlers.js
import { setupWorker, rest } from 'msw'
import { res } from './res'
const worker = setupWorker(
rest.get('/user', (req, _, ctx) => {
// Notice how this response resolver is using a custom `res` function
// imported at the top of this module.
return res(ctx.json({ firstName: 'John', lastName: 'Maverick' }))
}),
)
worker.start()
Most helpful comment
Hey, @garhbod. There's actually the very same usage example in the recently updated docs already: in the Custom response composition section. It illustrates how you can create your own
resfunction that has a random realistic response delay baked in. I find this more educational and practical as well, and see little reason to extend public API for this purpose.