Scott Hanselman

Exploring refit, an automatic type-safe REST library for .NET Standard

August 16, '17 Comments [21] Posted in DotNetCore | Open Source
Sponsored By

I dig everything that Paul Betts does. He's a lovely person and a prolific coder. One of his recent joints is called Refit. It's a REST library for .NET that is inspired by Square's Retrofit library. It turns your REST API into a live interface:

public interface IGitHubApi
{
[Get("/users/{user}")]
Task<User> GetUser(string user);
}

That's an interface that describes a REST API that's elsewhere. Then later you just make a RestService.For<YourInterface> and you go to town.

var gitHubApi = RestService.For<IGitHubApi>("https://api.github.com");

var octocat = await gitHubApi.GetUser("octocat");

imageThat's lovely! It is a .NET Standard 1.4 library which means you can use it darn near everywhere. Remember that .NET Standard isn't a runtime, it's a version interface - a list of methods you can use under many different ".NETs." You can use Refit on UWP, Xamarin.*, .NET "full" Frameowrk, and .NET Core, which runs basically everywhere.

Sure, you can make your own HttpClient calls, but that's a little low level and somewhat irritating. Sure, you can look for a .NET SDK for your favorite REST interface but what if it doesn't have one? It strikes a nice balance between the low-level and the high-level.

I'll give an example and use it as a tiny exercise for Refit. I have a service that hosts a realtime feed of my blood sugar, as I'm a Type 1 Diabetic. Since I have a Continuous Glucose Meter that is attached to me and sending my sugar details to a web service called Nightscout running in Azure, I figured it'd be cool to use Refit to pull my sugar info back down with .NET.

The REST API for Nightscout is simple, but doe have a lot of options, query strings, and multiple endpoints. I can start by making a simple interface for the little bits I want now, and perhaps expand the interface later to get more.

For example, if I want my sugars, I would go

https://MYWEBSITE/api/v1/entries.json?count=10

And get back some JSON data like this:

[
{
_id: "5993c4aa8d60c09b63ba1c",
sgv: 162,
date: 1502856279000,
dateString: "2017-08-16T04:04:39.000Z",
trend: 4,
direction: "Flat",
device: "share2",
type: "sgv"
},
{
_id: "5993c37d8d60c09b93ba0b",
sgv: 162,
date: 1502855979000,
dateString: "2017-08-16T03:59:39.000Z",
trend: 4,
direction: "Flat",
device: "share2",
type: "sgv"
}
]

Where "sgv" is serum glucose value, or blood sugar.

Starting with .NET Core 2.0 and the SDK that I installed from http://dot.net, I'll first make a console app from the command line and add refit like this:

C:\users\scott\desktop\refitsugars> dotnet new console
C:\users\scott\desktop\refitsugars> dotnet add package refit

Here's my little bit of code.

  • I made an object shaped like each record. Added aliases for weirdly named stuff like "sgv"
  • COOL SIDE NOTE: I added <LangVersion>7.1</LangVersion> to my project so I could have my public static Main entry point be async. That's new as many folks have wanted to have a "public static async void Main()" equivalent.

After that it's REALLY lovely and super easy to make a quick strongly-typed REST Client in C# for pretty much anything. I could see myself easily extending this to include the whole NightScout diabetes management API without a lot of effort.

using Newtonsoft.Json;
using Refit;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;

namespace refitsugars
{
public interface INightScoutApi
{
[Get("/api/v1/entries.json?count={count}")]
Task<List<Sugar>> GetSugars(int count);
}

public class Sugar
{
[JsonProperty(PropertyName = "_id")]
public string id { get; set; }

[JsonProperty(PropertyName = "sgv")]
public int glucose { get; set; }

[JsonProperty(PropertyName = "dateString")]
public DateTime itemDate { get; set; }
public int trend { get; set; }
}

class Program
{
public static async Task Main(string[] args)
{
var nsAPI = RestService.For<INightScoutApi>("https://MYURL.azurewebsites.net");
var sugars = await nsAPI.GetSugars(3);
sugars.ForEach(x => { Console.WriteLine($"{x.itemDate.ToLocalTime()} {x.glucose} mg/dl"); });
}
}
}

And here's the result of the run.

PS C:\Users\scott\Desktop\refitsugars> dotnet run
8/15/2017 10:29:39 PM 110 mg/dl
8/15/2017 10:24:39 PM 108 mg/dl
8/15/2017 10:19:40 PM 109 mg/dl

You should definitely check out Refit. It's very easy and quite fun. The fact that it targets .NET Standard 1.4 means you can use it in nearly all your .NET projects, and it already has creative people thinking of cool ideas.


Sponsor: Check out JetBrains Rider: a new cross-platform .NET IDE. Edit, refactor, test and debug ASP.NET, .NET Framework, .NET Core, Xamarin or Unity applications. Learn more and download a 30-day trial!

About Scott

Scott Hanselman is a former professor, former Chief Architect in finance, now speaker, consultant, father, diabetic, and Microsoft employee. He is a failed stand-up comic, a cornrower, and a book author.

facebook twitter subscribe
About   Newsletter
Sponsored By
Hosting By
Dedicated Windows Server Hosting by SherWeb
Wednesday, 16 August 2017 06:40:11 UTC
Thanks for the props! One tool that's super useful for Refit to write out your types is https://quicktype.io - get some sample JSON, then paste it in there, and it'll generate the C# goop for your data types
Wednesday, 16 August 2017 06:59:13 UTC
Hi Scott, thanks for this sharing !

What are you thoughts on AutoRest ?
We are using it and it generates services class and DTOs for us to import on our project based on a swagger interface.
Vincent THERRY
Wednesday, 16 August 2017 07:55:16 UTC
Thanks for Sharing
Nice Information
Wednesday, 16 August 2017 10:44:47 UTC
Very nice library!

It is aligned with the kind of developments we currently do at our company. Typically when we create an API, we create three projects (e.g. Api.Contracts, Api.Controller, Api.Client) where both the MVC controllers and client endpoints extend from the shared interfaces. This ensures no method is forgotten and we have a client for acceptance testing and that can also via distributed via a NuGet for clients that use .NET. My only problem has been a way to also share the urls from the interfaces.

Using this library I may find a way, with some custom route mapper for MVC, to do that while also having a client library that understands the same attributes.
João Simões
Wednesday, 16 August 2017 11:29:57 UTC
Thanks for sharing!

Yesterday @davidfowl mentioned in a tweet and motivated me to investigate the library. Really nice! My problem is that it does not run on Linqpad where I do a lot of testing these days. I mostly use Flurl.Http for that: http://tmenier.github.io/Flurl/
rmbrunet
Wednesday, 16 August 2017 12:51:04 UTC
Mads Kristensen had said a few years back that he / Microsoft were thinking about how to do "Add Service Reference" for REST APIs. It seems like that never went anywhere. That is really what should be happening here- it's ridiculous for a human to write any of this mindless glue code.

My brain screams out in agony seeing you hand type out that Sugar class. :)
Sam
Wednesday, 16 August 2017 13:42:05 UTC
I was in the middle of writing my own version of this. How the interface is set up (with method attributes as well as parameter attributes) is very similar to my own implementation. I'll definitely dive into this code soon! I'm interested to see how close our implementations are!
Brian Ball
Wednesday, 16 August 2017 15:02:18 UTC
I'm looking at the sample project you point to and doesn't it make more sense to have the interface T itself be registered in the DI container, rather than RestClient<T>
Richard Gavel
Wednesday, 16 August 2017 15:54:36 UTC
Useful sample, Thanks for sharing with us
Wednesday, 16 August 2017 16:21:10 UTC
Thanks for this one. Given Retrofits popularity for Android looks like it would be a great fit for Xamarin development.
Wednesday, 16 August 2017 21:15:05 UTC
Another library that provides a similar style to this for SQL is https://github.com/jonwagner/Insight.Database . It is a great way to get up and running quickly.
Andrew
Wednesday, 16 August 2017 23:02:14 UTC
Would love to give a quick shout-out to https://github.com/canton7/RestEase as well. Based on Refit and I do enjoy using them both equally!
Alex
Thursday, 17 August 2017 03:45:34 UTC
Thanks! It's cool.
Khanh Vu
Thursday, 17 August 2017 04:06:57 UTC
This library is ported from the Retrofit library that was originally created in Java.

Ref: https://github.com/square/retrofit
http://square.github.io/retrofit/

I explored the retrofit client library in one of my java projects but at that time it did not provide all the api's I need so I went back to use the RestTemplate client which was more mature and stable
alltej
Thursday, 17 August 2017 06:21:22 UTC
There is also another library based on RetroFit which is RestEase :

https://github.com/canton7/RestEase

Which also supports even lower netstandard1.1 and net45 and has some other additional features.
Stef Heyenrath
Thursday, 17 August 2017 11:50:04 UTC
I have been using Flurl... which is a joy to use!... but Refit makes it look even more fun!...
I will definitely give it a try in a new project soon..
rosdi
Thursday, 17 August 2017 11:51:25 UTC
Respect, Paul C. Betts :)
José Manuel
Saturday, 19 August 2017 12:31:56 UTC
I want you to thank for your time of this wonderful read!!! I definately enjoy every little bit of it and I have you bookmarked to check out new stuff of your blog a must read blog!!!!
Monday, 21 August 2017 00:53:22 UTC
Paul Betts is an amazing human.
David Rogers
Tuesday, 22 August 2017 18:28:03 UTC
Thanks a lot,
It helped me a lot
Monday, 28 August 2017 11:18:29 UTC
Comments are closed.

Disclaimer: The opinions expressed herein are my own personal opinions and do not represent my employer's view in any way.