question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Looking forwards to RestEase 2

See original GitHub issue

At some point, I’d like to move to RestEase 2. There are two main things want to achieve:

  1. Make use of source generators
  2. Make Json.NET optional

This issue is a brain dump, and a place to record my thoughts as they evolve.

Source Generators

Source generators are coming. They will essentially let NuGet packages hook into the build system, and insert their own code. This is a perfect fit for something like RestEase, where we can generate the implementation of a user’s interface at compile-time instead of at runtime.

However, I don’t want to remove support for the current IL emission approach.

As I understand it, the options available are:

  1. Let the user define partial classes with partial methods instead of interfaces, and generate the other part of the partial class.
  2. Keep the current approach of letting the user define an interface, and generate an implementation for that.

Partial classes have some appeal: they would let users write:

partial class MyApi
{
    [Get("foo")]
    partial Task FooAsync();
}

var api = new MyApi("https://api.example.com");

which avoids needing to use reflection. It also means the user can add their own concrete helper methods. However, there are some downsides: users like being able to define interfaces from an abstraction standpoint, and it would make the README significantly more complex (each code sample needs duplicating).

Continuing to use interfaces shouldn’t be too bad: we can emit an assembly-level attribute saying which generated type implements which interface, which we can pick up on at runtime.

Another consideration is what will happen if the source generator isn’t working. With a partial class, the compilation will fail. With interfaces, we simply won’t get an implementation generated, and we won’t know until runtime. I don’t know whether this might be an issue in practice.

We’d also want to keep the RestClient.For syntax for interfaces, presumably. However, I’d want both source generation and runtime IL generation to be opt-in, and allow both to run side-by-side, so RestClient would need to be defined in a central place, and do nasty things to make sure that it did runtime generation if necessary, and if possible. That could cause problems.

Identifying which partial classes / interfaces need implementations generated could be tricky: we don’t currently have a guaranteed type-level attribute, so we’d have to go looking through all methods of all types.

Json.NET

Json.NET is currently a mandatory dependency. That makes the simple case simpler, but means people who don’t want to use it still have to take a pointless dependency.

This never used to be much of a problem: most REST APIs are json, and everyone used Json.NET. However System.Text.Json is now a thing, and forcing people who want to use System.Text.Json to take a dependency on Json.NET is wrong.

However, we still need to support people who want to use Json.NET.

Backwards compatibility

Major version bumps are a good excuse to make breaking changes. I’m OK with breaking changes in principle, but they must be compile-time breakages (I don’t want things failing only at runtime), and there should ideally be guidance on how to solve it (e.g. use of Obsolete attributes).

Changes

I want to move all common types (attributes, RequestInfo, Requester, etc) to a RestEase.Core assembly. This is necessary to let source generation and runtime IL generation work side-by-side. These would stay in their current namespaces. It’s unclear what would happen to RestClient.

Currently the various serializers and deserializers are separate properties on RestClient. In order to let the user opt into the Json.NET (de)serializers easily, these would have to be grouped on a new object. Then the user could do new RestClient() { Serializers = new JsonNetSerializers() } or similar. The JsonSerializerSettings would have to be removed from RestClient as well.

We’d need a RestEase.Json.NET NuGet package which contains the Json.NET (de)serializers.

Presumably we’d want two more NuGet packages, one for the source generators and one for the runtime IL emission (they can’t be the same package, because the source generators shouldn’t have a dependency on ILBuilder).

It’s unclear what should happen to the current RestEase NuGet package. Maybe this should continue to contain the IL emission code, or maybe it should be a backwards-compatibility meta-package which references the IL emission NuGet package, as well as the RestEase.Json.NET NuGet package.

Other Changes

It’s also a chance to tackle #19, and not assume that responses are always strings. This needs more thought.

Issue Analytics

  • State:open
  • Created 3 years ago
  • Reactions:12
  • Comments:15 (10 by maintainers)

github_iconTop GitHub Comments

2reactions
canton7commented, May 10, 2020

I’ve been mulling over this further, and I’m leaning in favour of keeping things as a single package. This would include the source analyzer and the S.R.E implementation. The S.R.E would be used as a fallback in case the source generator fails, or isn’t available (on platforms which support it).

This makes life a lot simpler: people don’t have to make informed decisions at the point of installing the library (which is a hurdle). They install the RestEase package, and if their toolchain supports source generators, they get nice compile-time error messages; if it doesn’t, things work as before (except on Xamarin.iOS, where they’ll get a nice exception message pointing them at the docs for source generators).

This does mean we’ll ship a S.R.E implementation to platforms which don’t support it, but that’s probably OK. .NET Standard 2.1 includes S.R.E (and the latest Xamarin versions target .NET Standard 2.1), so we won’t have an extraneous dependency on the S.R.E NuGet package

There is the thorny issue of what to do about the Newtonsoft.Json dependency, though. Intuitively, we should target System.Text.Json by default, but 1) that’s only supported on some platforms, so we’ll get different behaviour depending on the platform, and 2) that ends up going down the route of silently switching people from Newtonsoft.Json to System.Text.Json, which is going to break things for some people. Therefore I think we have the following options:

  1. Deprecate RestEase (NuGet supports this now) and switch to RestEase2. The migration notes tell people what to do in order to keep using Newtonsoft.Json (whatever that may be).
  2. Detect whether Newtonsoft.Json is loaded and automatically switch to it. I don’t like this at all: installing an unrelated package will silently change the behaviour of RestEase.
  3. Don’t target any json library by default, and force the user to explicitly opt into one. We’d want a nice way to opt into a library, such as an attribute on the interface (which is something I’ve been thinking of anyway: the current approach of putting that config on the RestClient removes it from the code which actually uses it). We would need logic to detect when the user is trying to use an interface which needs serializer support (check for method return types which need deserializing; SerializationMethod, etc), and throw a suitably informative error message. We will break some users this way, however.
  4. Something similar to what I was thinking of before: RestEase becomes some sort of compatibility package which references the “main” RestEase NuGet package, and also the Newtonsoft.Json RestEase package. It needs some way to tell the main RestEase package that the Newtonsoft.Json package is available however, and this gets ugly.
1reaction
canton7commented, Jan 21, 2023

You can write your own serializer which uses STJ - the only side is you’ll bring in json.net as a dependency, even though it’s unused.

There’s also a third party fork of RestEase on nuget, although I can’t vouch for it

Read more comments on GitHub >

github_iconTop Results From Across the Web

RestEase
RestEase. Easy-to-use typesafe REST API client library for .NET Core, which is simple and customisable. Inspired by Refit. Become a Bounty Hunter
Read more >
RestEase
Easy-to-use typesafe REST API client library for .NET Standard 1.1 and .NET Framework 4.5 and higher, which is simple and customisable. Inspired by...
Read more >
Using the REST Client
This guide explains how to use the REST Client Reactive in order to interact with REST APIs. REST Client Reactive is the REST...
Read more >
I'm looking forward to hearing from you ...
1. I'm eagerly awaiting your response. · 2. Your prompt response would be appreciated. · 3. Thank you for your timely response. ·...
Read more >
8 Alternatives to “Looking Forward to Hearing from You”
Some good alternatives to “looking forward to hearing from you” are “keep me informed” and “I'd love to hear your feedback.”
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found