Refitter 0.3.3

There is a newer version of this package available.
See the version list below for details.
dotnet tool install --global Refitter --version 0.3.3                
This package contains a .NET tool you can call from the shell/command line.
dotnet new tool-manifest # if you are setting up this repo
dotnet tool install --local Refitter --version 0.3.3                
This package contains a .NET tool you can call from the shell/command line.
#tool dotnet:?package=Refitter&version=0.3.3                
nuke :add-package Refitter --version 0.3.3                

Refitter

Refitter is a CLI tool for generating a C# REST API Client using the Refit library. Refitter can generate the Refit interface from OpenAPI specifications

Installation:

The tool is packaged as a .NET Tool and is published to nuget.org. You can install the latest version of this tool like this:

dotnet tool install --global Refitter

Usage:

$ refitter --help
USAGE:
    refitter [input file] [OPTIONS]

EXAMPLES:
    refitter ./openapi.json --namespace "Your.Namespace.Of.Choice.GeneratedCode" --output ./Output.cs

ARGUMENTS:
    [input file]    Path to OpenAPI Specification file

OPTIONS:
                                      DEFAULT                                                          
    -h, --help                                         Prints help information                         
    -n, --namespace                   GeneratedCode    Default namespace to use for generated types    
    -o, --output                      Output.cs        Path to Output file                             
        --no-auto-generated-header                     Don't add <auto-generated> header to output file
        --interface-only                               Don't generate contract types                   

To generate code from an OpenAPI specifications file, run the following:

$ refitter [path to OpenAPI spec file] --namespace "[Your.Namespace.Of.Choice.GeneratedCode]"

This will generate a file called Output.cs which contains the Refit interface and contract classes generated using NSwag

Using the generated code

Here's an example generated output from the Swagger Petstore example

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

namespace Your.Namespace.Of.Choice.GeneratedCode
{
    public interface ISwaggerPetstore
    {
        /// <summary>
        /// Update an existing pet by Id
        /// </summary>
        [Put("/pet")]
        Task<Pet> UpdatePet([Body]Pet body);

        /// <summary>
        /// Add a new pet to the store
        /// </summary>
        [Post("/pet")]
        Task<Pet> AddPet([Body]Pet body);

        /// <summary>
        /// Multiple status values can be provided with comma separated strings
        /// </summary>
        [Get("/pet/findByStatus")]
        Task<ICollection<Pet>> FindPetsByStatus([Query]Status? status);

        /// <summary>
        /// Multiple tags can be provided with comma separated strings. Use tag1, tag2, tag3 for testing.
        /// </summary>
        [Get("/pet/findByTags")]
        Task<ICollection<Pet>> FindPetsByTags([Query(CollectionFormat.Multi)]ICollection<string> tags);

        /// <summary>
        /// Returns a single pet
        /// </summary>
        [Get("/pet/{petId}")]
        Task<Pet> GetPetById(long? petId);

        [Post("/pet/{petId}")]
        Task UpdatePetWithForm(long? petId, [Query]string name, [Query]string status);

        [Delete("/pet/{petId}")]
        Task DeletePet(long? petId);

        [Post("/pet/{petId}/uploadImage")]
        Task<ApiResponse> UploadFile(long? petId, [Query]string additionalMetadata, [Body]StreamPart body);

        /// <summary>
        /// Returns a map of status codes to quantities
        /// </summary>
        [Get("/store/inventory")]
        Task<IDictionary<string, int>> GetInventory();

        /// <summary>
        /// Place a new order in the store
        /// </summary>
        [Post("/store/order")]
        Task<Order> PlaceOrder([Body]Order body);

        /// <summary>
        /// For valid response try integer IDs with value <= 5 or > 10. Other values will generated exceptions
        /// </summary>
        [Get("/store/order/{orderId}")]
        Task<Order> GetOrderById(long? orderId);

        /// <summary>
        /// For valid response try integer IDs with value < 1000. Anything above 1000 or nonintegers will generate API errors
        /// </summary>
        [Delete("/store/order/{orderId}")]
        Task DeleteOrder(long? orderId);

        /// <summary>
        /// This can only be done by the logged in user.
        /// </summary>
        [Post("/user")]
        Task CreateUser([Body]User body);

        /// <summary>
        /// Creates list of users with given input array
        /// </summary>
        [Post("/user/createWithList")]
        Task<User> CreateUsersWithListInput([Body]ICollection<User> body);

        [Get("/user/login")]
        Task<string> LoginUser([Query]string username, [Query]string password);

        [Get("/user/logout")]
        Task LogoutUser();

        [Get("/user/{username}")]
        Task<User> GetUserByName(string username);

        /// <summary>
        /// This can only be done by the logged in user.
        /// </summary>
        [Put("/user/{username}")]
        Task UpdateUser(string username, [Body]User body);

        /// <summary>
        /// This can only be done by the logged in user.
        /// </summary>
        [Delete("/user/{username}")]
        Task DeleteUser(string username);
    }
}

RestService

Here's an example usage of the generated code above

using Refit;
using System;
using System.Threading.Tasks;

namespace Your.Namespace.Of.Choice.GeneratedCode;

internal class Program
{
    private static async Task Main(string[] args)
    {
        var client = RestService.For<ISwaggerPetstore>("https://petstore3.swagger.io/api/v3");
        var pet = await client.GetPetById(2);

        Console.WriteLine($"Name: {pet.Name}");
        Console.WriteLine($"Category: {pet.Category.Name}");
        Console.WriteLine($"Status: {pet.Status}");
    }
}

The RestService class generates an implementation of ISwaggerPetstore that uses HttpClient to make its calls.

The code above when run will output something like this:

Name: Gatitotototo
Category: Chaucito
Status: Sold

ASP.NET Core and HttpClientFactory

Here's an example Minimal API with the Refit.HttpClientFactory library:

using Refit;
using Your.Namespace.Of.Choice.GeneratedCode;

var builder = WebApplication.CreateBuilder(args);
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
builder.Services
    .AddRefitClient<ISwaggerPetstore>()
    .ConfigureHttpClient(c => c.BaseAddress = new Uri("https://petstore3.swagger.io/api/v3"));

var app = builder.Build();
app.MapGet(
        "/pet/{id:long}",
        async (ISwaggerPetstore petstore, long id) =>
        {
            try
            {
                return Results.Ok(await petstore.GetPetById(id));
            }
            catch (Refit.ApiException e)
            {
                return Results.StatusCode((int)e.StatusCode);
            }
        })
    .WithName("GetPetById")
    .WithOpenApi();

app.UseHttpsRedirection();
app.UseSwaggerUI();
app.UseSwagger();
app.Run();

.NET Core supports registering the generated ISwaggerPetstore interface via HttpClientFactory

The following request to the API above

$ curl -X 'GET' 'https://localhost:5001/pet/1' -H 'accept: application/json'

Returns a response that looks something like this:

{
  "id": 1,
  "name": "Special_char_owner_!@#$^&()`.testing",
  "photoUrls": [
    "https://petstore3.swagger.io/resources/photos/623389095.jpg"
  ],
  "tags": [],
  "status": "Sold"
}

System requirements

.NET 7.0

For tips and tricks on software development, check out my blog

If you find this useful and feel a bit generous then feel free to buy me a coffee ☕

Product Compatible and additional computed target framework versions.
.NET net7.0 is compatible.  net7.0-android was computed.  net7.0-ios was computed.  net7.0-maccatalyst was computed.  net7.0-macos was computed.  net7.0-tvos was computed.  net7.0-windows was computed.  net8.0 was computed.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

This package has no dependencies.

Version Downloads Last updated
1.3.2 92,126 9/23/2024
1.3.2-preview.60 34 9/23/2024
1.3.1 48,938 9/20/2024
1.3.0 96,736 9/14/2024
1.2.1-preview.59 45 9/13/2024
1.2.1-preview.58 60 9/11/2024
1.2.1-preview.57 43 9/11/2024
1.2.1-preview.56 57 9/9/2024
1.2.1-preview.55 3,220 9/2/2024
1.2.1-preview.54 4,698 8/29/2024
1.2.0 559,330 8/12/2024
1.2.0-preview.53 5,173 8/4/2024
1.2.0-preview.52 1,833 7/29/2024
1.1.3 359,773 7/19/2024
1.1.3-preview.51 42 7/19/2024
1.1.2 25,443 7/17/2024
1.1.2-preview.50 39 7/16/2024
1.1.2-preview.49 53 7/11/2024
1.1.1 188,745 7/6/2024
1.1.1-preview.48 60 7/4/2024
1.1.1-preview.47 55 7/1/2024
1.1.1-preview.46 52 6/28/2024
1.1.0.45-preview 93 6/25/2024
1.0.2 238,527 6/13/2024
1.0.1 48,327 6/7/2024
1.0.0 244,531 5/3/2024
0.9.9.44-preview 81 4/29/2024
0.9.9 8,085 3/7/2024
0.9.8 3,445 2/27/2024
0.9.7 71,975 2/7/2024
0.9.6 248 1/29/2024
0.9.5 37,949 1/15/2024
0.9.4.43-preview 115 1/15/2024
0.9.4 32,072 1/12/2024
0.9.3.42-preview 149 1/10/2024
0.9.2 20,104 1/10/2024
0.9.1 3,890 1/9/2024
0.9.0 3,090 1/9/2024
0.8.7.41-preview 153 1/3/2024
0.8.7.40-preview 129 12/20/2023
0.8.7 55,020 12/18/2023
0.8.6.39-preview 146 12/14/2023
0.8.6.38-preview 161 12/14/2023
0.8.6 3,537 12/11/2023
0.8.5 54,206 11/23/2023
0.8.4 382 11/7/2023
0.8.3 242 10/31/2023
0.8.2 431 10/9/2023
0.8.1 888 10/4/2023
0.8.0 1,740 9/23/2023
0.7.5 2,722 9/7/2023
0.7.4 338 9/6/2023
0.7.3.37-preview 213 8/25/2023
0.7.3.36-preview 234 8/25/2023
0.7.3.35-preview 246 8/21/2023
0.7.3.34-preview 249 8/15/2023
0.7.3.33-preview 231 8/12/2023
0.7.3 2,016 8/26/2023
0.7.2.32-preview 210 8/7/2023
0.7.2 3,802 8/7/2023
0.7.1.31-preview 243 8/2/2023
0.7.1.30-preview 181 8/2/2023
0.7.1.29-preview 246 8/1/2023
0.7.1 695 8/3/2023
0.7.0.28-preview 170 7/28/2023
0.7.0.27-preview 275 7/28/2023
0.7.0.26-preview 252 7/27/2023
0.7.0.23-preview 237 7/27/2023
0.7.0.22-preview 290 7/27/2023
0.7.0.21-preview 226 7/27/2023
0.7.0.20-preview 271 7/27/2023
0.7.0 411 7/31/2023
0.6.3 1,155 7/22/2023
0.6.2 11,817 6/22/2023
0.6.1 329 6/20/2023
0.6.0 700 6/15/2023
0.5.30 472 6/12/2023
0.5.29 142 6/12/2023
0.5.28 154 6/10/2023
0.5.27 205 5/24/2023
0.5.26 267 5/11/2023
0.5.25 189 5/10/2023
0.5.3 180 5/5/2023
0.5.2 145 5/2/2023
0.5.1 161 5/2/2023
0.5.0 206 4/28/2023
0.4.2 199 4/24/2023
0.4.1 423 4/3/2023
0.4.0 303 3/24/2023
0.3.17 6,440 3/24/2023
0.3.16 248 3/22/2023
0.3.4 210 3/22/2023
0.3.3 296 3/17/2023
0.3.2 263 3/16/2023
0.3.1 239 3/14/2023
0.3.0 229 3/14/2023
0.2.4-alpha 265 3/1/2023
0.2.3-alpha 173 2/27/2023
0.2.2-alpha 214 2/25/2023
0.2.1-alpha 241 2/25/2023
0.2.0-alpha 190 2/24/2023
0.1.5-alpha 245 2/18/2023
0.1.4-alpha 287 2/17/2023
0.1.3-alpha 266 2/17/2023
0.1.2-alpha 237 2/17/2023