Open
Description
Hi, Working on a project which requires HTTP mocking. Things works so far very well with the mockttp
.
The only thing I am struggling with right now to implement the event stream. If we can have access to the response
object that we can pass to our code which write events periodically that would solve the problem.
Any suggestions on how to do it the right way with mockttp
?
Metadata
Metadata
Assignees
Labels
No labels
Activity
pimterry commentedon Jul 28, 2022
Hi @nazarhussain. To be honest, this isn't well supported, but I think it should be possible for simple cases using
thenStream
. Does that work for you?If not, can you explain more about what you're trying to do? I'm definitely interested in better supporting this in future, and it'd be useful to understand the use cases that are important.
nazarhussain commentedon Jul 28, 2022
Yes, I tried
thenStream
but could not help out well. Points are highlighted below:thenStream
requires sending a pre-initialized streamThe use-case I have is the following:
event-stream
that I want to reusehandler
to be passed for events of interest categorized by topicsWe are using fastify for actual implementation and I wanted to mock to test some complex scenarios. Here you can find the reference to real handling of those event streams.
https://github.com/ChainSafe/lodestar/blob/384e3931c939b04353964524b52969e4f1a4f307/packages/api/src/beacon/server/events.ts#L15-L58
pimterry commentedon Jul 28, 2022
Ah, I see, that makes sense. Yes, I think that's not really supported right now. You could try creating many rules each matching different sets of parameters and returning different streams, but that won't work for many cases (e.g. completely unknown freeform query params) and it's quite awkward.
In future, I think this would probably be best supported by allowing it within
thenCallback
, with something like:Doing this perfectly is a little harder than it sounds in some places - for example in the general case, the stream needs to be automatically encoded, whilst it's streaming, using the appropriate compression algorithm (e.g. gzip). I think we can avoid that initially, but we'd need to do so explicitly...
How about we extend the result type from callbacks, so that the
rawBody
field can be returned with either a Buffer, or a Buffer stream?rawBody
is never encoded - if you use it, you're responsible for handling encoding yourself - but I think that's probably fine for your case. We could then add stream support with automatic encoding in thebody
parameter later on, if necessary, with no breaking changes.I'm open to something like this. I'm unlikely to have much time in the short-term to look into it myself, but PRs are very welcome.
nazarhussain commentedon Jul 28, 2022
How about we have
thenCallback
support to returnstream
and where users will be responsible for writing to stream the way they wanted.pimterry commentedon Jul 28, 2022
I'm not sure exactly what you mean, can you show an example?
nazarhussain commentedon Aug 1, 2022
Currently the
thenCallback
supports different options to return, e.g.json
,body
. What if we can returnstream
from there? We can prepare the stream withinthenCallback
and return likereturn { stream: myStream }
.pimterry commentedon Aug 1, 2022
Yes, exactly. I think maybe you've misunderstood my example? That's effectively the same as what I'm proposing in the example above.
The only difference is that in that case, we return the stream as another type of value for the existing body field, instead of a adding a new separate
stream
field. Does that make sense? It's useful that way because it's never meaningful to return both at the same time, and returning a stream there is unambiguous (because it's currently not a valid value for that field).It's also better to start with just
rawBody
, notbody
, to make it clear that the stream data will not be automatically encoded (we can do that later, but it's not needed immediately, and it's not easy). We can do both later though, to support both pre-encoded & unencoded body streams.Anyway, yust to make it clearer, I'm proposing that this would work:
Is that clearer?
rageshkrishna commentedon May 18, 2023
Hi @pimterry! I took a stab at this and tried to change
CallbackResponseMessageResult.rawBody
toBuffer | Uint8Array | Readable
and I soon realized that this also affects thebeforeRequest
andbeforeResponse
paths, becausebuildOverriddenBody
was written to expect a completerawBody
and not something that is still streaming.Would having a stream be useful at all in
beforeRequest
andbeforeResponse
? I'm wondering if I could just add something likeCallbackResponseMessageResult.bodyStream
that's only used bywriteResponseFromCallback
. I was able to get that working rather quickly and have tests passing, but would it make sense to add a new property just for this? Do you see a better way to do this?EDIT: Or, maybe read the whole stream into a buffer in
buildOverriddenBody
?rageshkrishna commentedon May 18, 2023
Opened a PR for this feature. I'd love to get some feedback on it. Thanks!