-
-
Notifications
You must be signed in to change notification settings - Fork 107
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
String responses are not passed to Response Deserializer #19
Comments
Indeed, that's the defined behaviour. With JSON that's sensible behaviour, as a bare string is not valid JSON. My understanding is that the same is true for protobuf - it's legal to send messages around, but not just primitives? SO seems to think so. When you say that you use RestEase with a protobuf serializer, do you mean that you're talking to a REST endpoint which returns binary responses in protobuf format? If so, using RestEase with a custom serializer is probably not the right thing to do: it will try and read the response as a string, and could fall over as not every byte sequence is a valid string. There's a better approach, but I'll only go into if it it's relevant here. |
Hmm. Fair enough. But yes, i'm using protobuf-net and requesting a custom media type from a REST endpoint (which is protobuf formatted), hence running into this. Would be interested in the better approach though. Else can always fall back on not returning string primitives. But in general, proto or no proto. If you provide a custom deserializer support, it's non-intuitive to do the string pass through? The assumption that HTTP protocol content string equals the string type data payload doesn't seem right when you have a custom deserializer in the middle. Edit: on the reading bytes as string, i just make sure in the deserialization to read the content stream and not as a string. |
If your endpoint is returning raw binary data, you really need to be subclassing While you're there, you can override I can see your argument for passing
In theory, I'm in favour of better support for binary endpoints in RestEase, since that's apparently a use-case. This wouldn't be first-class support, but probably an alternative
As the SO post I linked to says, passing a raw string gives you no forwards compatibility. You can't add anything to the response without breaking existing consumers. This somewhat defeats the point of protobuf. |
Okay. Fair enough. Glancing at the code, the custom requester looks like a good place to start. Will close the issue as backward compatibility seems to put a full stop to this being changed... I will come back and say though that the custom serializer support then completely blows up as a paradigm. Both as you already read the content as string instead of passing in the raw content to be interpreted as well as this string interception. The whole point of a custom serializer is that i get to use the requester and routing without any judgements on the data payload. I don't think it's valid to say "strings will blow up anyways". If someone is using a relatively sophisticated feature, they ought to be able to handle their protocol specific cases. Point 2 also kinda makes sense, but only on the surface. You have a type-safe rest client, by definition. And support for custom serialization. So where's the excuse to read and pass raw API response strings? Only for testing, exploration and that's best done in a browser or elsewhere. I guess it comes back to the custom serialization aspect feeling pretty leaky (and that was the reason to try here over Refit). |
Reopening, as I want to think about binary requester support.
That's not correct. RestEase makes an assumption that the endpoint returns a string, and it does this in order to make the majority use-case smoother for people. It's a custom string deserializer, if you prefer.
Unfortunately it's not possible to make assumptions like this. You can guarantee that, whatever your assumptions, someone will come along with a use-case which breaks all of them. I can guarantee that, somewhere, someone wants a raw string. Maybe RestEase's deserialization abstractions aren't enough for them to do their own deserialization? Maybe they just want to log the response, but not interpret it? You're a perfect example of this: you've got a binary endpoint, and you're breaking the spec for the binary protocol you're using. And yet RestEase still has ways to help you, but only because I didn't assume that people would never want to customise exactly how requests were formed and responses handled.
When you're writing a tool which gives people a better experience for the majority use case, you have to make assumptions and simplifications. That's the very nature of what you're doing: by making assumptions about what people are trying to do, you can make life easier for them. If you don't want to make assumptions, you can't do better than A good library will provide multiple layers: if the highest level of abstraction doesn't work, users can fall back to writing a bit more code and being able to customise the behaviour a bit further. This is what RestEase does.
If the custom serializers layer didn't assume you were working with text, then life would be harder for that majority which are working with text. It wouldn't be achieving its aim of making life easier for the majority. In hindsight, if I wanted to add first-class support for binary endpoints from the start, I would have structured You obviously have your own expectations about where each of the layers of abstraction should stop and start, and that's OK, but sadly irrelevant. I had my own ideas when I defined them, and that's what got written. If you were around to ask when I was designing RestEase I'm sure I'd have taken your opinion into consideration, but you weren't, so I went with what I thought they should be.
That's what I talked about above. If someone is using a relatively sophisticated feature, they have to fall back to a lower level of abstraction (in this case, back to Subclassing |
Cool. Thanks for taking the time to respond. It just comes back to expectation mismatch then. Written a little code with a custom requester, should be easy enough to integrate. It's fair to have the string/text slant as after all this is HTTP, i suppose i just expected "custom serializer" to mean only that, custom handling of a data payload. Thanks again for the help. |
No problem. I'm happy to update the README to clarify the stringy nature of most of RestEase, and point people who want to talk binary in the right direction (including providing a sample |
Hi, I have to say, I really like RestEase. So I just tried it and it just worked. I've injected my own authorisation, used custom deserializer. Works great, but before switching from RestSharp (and transitioning to .NET core), I would like to ask for one modification. NOTE: Actually I can implement changes myself, and send you pull request. I would like to have your approval prior to that, though. My data always travels wrapped in some kind of envelope. Let's call it The only problem is for The non-breaking solution I can think of would be:
In such case:
Optional improvement: Note: I don't like the name |
I wonder whether a better way would be to have two methods on the deserializer, one for string responses and one for T responses. That requires a breaking change to the deserializer interface, but that's less disruptive IMO. We can change it to be an abstract base class at the same time to avoid breakages in the future. |
I think I can change to abstract base classes instead of interfaces without breaking backwards compatibility if I'm careful (I'll add deprecation notices but they won't be mandatory). |
@canton7 As I understand binary response support was not implemented yet. |
There are two things going on here. The first is that RestEase will try and read the response as a string in many cases, and a return type of However deserializers do have direct access to the response stream, (and request serializers just have access to whatever type is being serialized). If your return type is
The long-term plan is to change the deserialize method to be async (as it's a little less confusing for people), and to not receive the body as a string (which can now be done in a backwards-compatible manner). We'll also pass responsibility to handling a return type of |
That is true if you look at json.org, but has been superseded in 2014 by RFC-7159 and ECMA-404. From RFC-7159:
So arguably RestEase is doing the wrong thing here if the server returns a body of the form |
See #230 - as part of the fix for that, I've introduced |
Hi,
I'm finding that if a route has a return type as string, the http content from the response is directly passed back instead of being first sent to the deserializer. It might be a saving but it's wrong in the case of custom deserializers.
I use restease exclusively with a protobuf-net serializer and this causes a rather unexpected gotcha as you can imagine. As i get the protobuf message directly interpreted as a string...
Let me know if that makes sense? Can dig around and make the PR if it helps. Thanks.
The text was updated successfully, but these errors were encountered: