reactiveui / refit

The automatic type-safe REST library for .NET Core, Xamarin and .NET. Heavily inspired by Square's Retrofit library, Refit turns your REST API into a live interface.
https://reactiveui.github.io/refit/
MIT License
8.67k stars 745 forks source link

Structured Refit HttpClient #1142

Open legiosys opened 3 years ago

legiosys commented 3 years ago

Hello!

First, thanks for your work, it's realy powerfull project!

Our problem: We have for example three controllers: QueryController, ChangeController and UtilityController. We create Refit interfaces: IQueryController,.. and implement by controllers. Now, if we don't want to be wrong what method we should use, we name methods like Query_GetSmth. We create "super" interface ISomeService : IQueryController, ChangeController, UtilityController and use it for RestService.

It wil be good to create refit client from interface like this:

public interface ISomeService
    {
        IQueryController Query { get; }
    }

public interface IQueryController
    {
        [Get(Routes.GetSmth)]
        Task<Smth> GetSmth(int id);
    }

And then we can call method like:

var client = RestService.For<ISomeService>("http://localhost:5000");
var result = client.Query.GetSmth(id);

May be need add attribute like [RestService] that have AttributeTargets.Interface and then we can catch this interfaces in Source Generator:

[RestService]
public interface ISomeService
    {
        IQueryController Query { get; }
    }
class SyntaxReceiver : ISyntaxReceiver
        {
            public List<MethodDeclarationSyntax> CandidateMethods { get; } = new();

            public List<InterfaceDeclarationSyntax> CandidateInterfaces { get; } = new();

            public List<InterfaceDeclarationSyntax> CandidateServiceInterfaces { get; } = new();

            public void OnVisitSyntaxNode(SyntaxNode syntaxNode)
            {
                //...
                if(syntaxNode is InterfaceDeclarationSyntax iface && iface.AttributeLists.Count > 0)
                {
                    CandidateServiceInterfaces.Add(iface);
                }
            }
        }

And after generate SomeService : ISomeService with properties like IQueryController Query = GeneratedQueryControllerClient.

Thanks.

aeb-dev commented 3 years ago

How about this:

[RefitClient]
public interface ISomeClient : ISome
{
}
public interface ISome
{
      [Get("some")]
      Task Some();
}

And you just use ISomeClient and you will have access to all of the functions.

legiosys commented 3 years ago

And you just use ISomeClient and you will have access to all of the functions.

In this case:

public interface ISomeEntities
{
      [Get("someEntities/GetById")]
      Task GetById(int id);
}
public interface IAnotherEntities
{
      [Get("anotherEntities/GetById")]
      Task GetById(int id);
}
public interface ISomeClient : ISomeEntities, IAnotherEntities
{}

What result will be when we call ISomeClient.GetById?

Now we solve this with Reflection: We generate SomeClientService from interface and set for IRefitInterface properties refit generated implementations RestService.For<IRefitInterface>