Exploring refit, an automatic type-safe REST library for .NET Standard
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");
That'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.
About Newsletter
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.
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.
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/
My brain screams out in agony seeing you hand type out that Sugar class. :)
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
https://github.com/canton7/RestEase
Which also supports even lower netstandard1.1 and net45 and has some other additional features.
I will definitely give it a try in a new project soon..
Comments are closed.