lundberg / respx

Mock HTTPX with awesome request patterns and response side effects 🦋
https://lundberg.github.io/respx
BSD 3-Clause "New" or "Revised" License
581 stars 38 forks source link

Add type based matching #239

Open macieyng opened 1 year ago

macieyng commented 1 year ago

I was thinking that it would be useful to have typed based matching. One of the use cases would when app sends an generated uuid and all you care about is if the type is correct and doesn't really care about specific value.

ie.

import uuid
import respx
import httpx

respx_mock.post("http://example.com", json={"id": uuid.UUID})
httpx.post("http://example.com", json={"id": uuid.uuid4()}  # should be mocked by respx

This could be extended to other types like simple types, types from typing module, etc.

WDYT?

lundberg commented 1 year ago

Lets break it down ...

Currently the json= pattern only supports the EQUAL lookup, and is using json dump (string) to compare the left and right side. This means that the right hand side needs to be json serializable at the moment.

First thing to solve would probably be to extend the json pattern and add support for the other lookups, e.g. contains, in, startswith etc, so that we can support a pattern lookup like json__id__in=[1, 2, 3].

If we also add support for Any, like some of the other patterns do, we could then do json__id=Any.

This doesn't solve your type issue, though.

To only match the specific type, we could either add a new lookup, e.g. __type=, once multi lookup is support by json pattern ... or the user (you) builds a specific class that implements __eq__ and only validates the type, e.g. json__id=AnyUUID.

macieyng commented 1 year ago

Thanks for the explanation. Can I help somehow?

lundberg commented 1 year ago

Thanks for the explanation. Can I help somehow?

The JSON pattern needs to be adjusted to not hash/dump when the pattern has a path .. I think that would at least open up support for comparing against other types, e.g. Any or custom.

At least we can start with that, and wait with other lookups to begin with.

Though, I think not hashing should depend on the type of the value provided, e.g. if a list or dict is passed, then I think it's best to keep it hash dumped .. example json__foo__bar={"ham": "spam"} would be easiest if it was kept compared with current hash, but an example like json__foo__bar__ham="spam" could potentially just be compared without hash and therefor allow json__foo__bar__ham=Any.

So, might be possible to only adjust and enhance the hash method on JSON pattern 🤞